
001package org.hl7.fhir.convertors.misc; 002 003import java.io.IOException; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.HashMap; 007import java.util.HashSet; 008import java.util.List; 009import java.util.Map; 010import java.util.Set; 011 012/* 013 Copyright (c) 2011+, HL7, Inc. 014 All rights reserved. 015 016 Redistribution and use in source and binary forms, with or without modification, 017 are permitted provided that the following conditions are met: 018 019 * Redistributions of source code must retain the above copyright notice, this 020 list of conditions and the following disclaimer. 021 * Redistributions in binary form must reproduce the above copyright notice, 022 this list of conditions and the following disclaimer in the documentation 023 and/or other materials provided with the distribution. 024 * Neither the name of HL7 nor the names of its contributors may be used to 025 endorse or promote products derived from this software without specific 026 prior written permission. 027 028 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 029 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 030 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 031 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 032 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 033 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 034 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 035 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 036 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 037 POSSIBILITY OF SUCH DAMAGE. 038 039 */ 040 041 042import org.fhir.ucum.UcumEssenceService; 043import org.fhir.ucum.UcumService; 044import org.hl7.fhir.dstu3.formats.IParser.OutputStyle; 045import org.hl7.fhir.dstu3.formats.XmlParser; 046import org.hl7.fhir.dstu3.model.CodeSystem; 047import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; 048import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; 049import org.hl7.fhir.dstu3.model.CodeSystem.PropertyType; 050import org.hl7.fhir.dstu3.model.CodeType; 051import org.hl7.fhir.dstu3.model.Coding; 052import org.hl7.fhir.dstu3.model.ConceptMap; 053import org.hl7.fhir.dstu3.model.ConceptMap.ConceptMapGroupComponent; 054import org.hl7.fhir.dstu3.model.ConceptMap.SourceElementComponent; 055import org.hl7.fhir.dstu3.model.ConceptMap.TargetElementComponent; 056import org.hl7.fhir.dstu3.model.ContactDetail; 057import org.hl7.fhir.dstu3.model.ContactPoint; 058import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem; 059import org.hl7.fhir.dstu3.model.DateTimeType; 060import org.hl7.fhir.dstu3.model.Enumerations.ConceptMapEquivalence; 061import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus; 062import org.hl7.fhir.dstu3.model.Identifier; 063import org.hl7.fhir.dstu3.model.StringType; 064import org.hl7.fhir.dstu3.model.UriType; 065import org.hl7.fhir.exceptions.FHIRException; 066import org.hl7.fhir.utilities.CSVReader; 067import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 068import org.hl7.fhir.utilities.Utilities; 069import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 070 071@SuppressWarnings("checkstyle:systemout") 072public class IEEE11073Convertor { 073 074 public static final String UCUM_PATH = "c:\\work\\org.hl7.fhir\\build\\implementations\\java\\org.hl7.fhir.convertors\\samples\\ucum-essence.xml"; 075 private static final String MDC_ALL_VALUES = "http://????"; 076 077 /** 078 * argument 1: path to the rosetta csv file 079 * argument 2: basePath to produce files to 080 * 081 * @param args 082 * @throws Exception 083 */ 084 public static void main(String[] args) throws Exception { 085 UcumService ucum = new UcumEssenceService(UCUM_PATH); 086 087 CodeSystem mdc = generateMDC(args[0], args[1], ucum); 088 ConceptMap loinc = generateLoincMdcMap(mdc, args[1], args[2]); 089 } 090 091 private static ConceptMap generateLoincMdcMap(CodeSystem mdc, String dst, String src) throws IOException, FHIRException { 092 ConceptMap cm = new ConceptMap(); 093 cm.setId("loinc-mdc"); 094 cm.setUrl("http:/???/fhir/ConceptMap/loinc-mdc"); 095 cm.setVersion("[todo]"); 096 cm.setName("LoincMdcCrossMap"); 097 cm.setTitle("Cross Map between LOINC and MDC"); 098 cm.setStatus(PublicationStatus.DRAFT); 099 cm.setExperimental(true); 100 cm.setDateElement(new DateTimeType()); 101 cm.setPublisher("HL7, Inc"); 102 ContactDetail cd = cm.addContact(); 103 cd.setName("LOINC + IEEE"); 104 ContactPoint cp = cd.addTelecom(); 105 cp.setSystem(ContactPointSystem.URL); 106 cp.setValue("http://loinc.org"); 107 cm.setDescription("A Cross Map between the LOINC and MDC Code systems"); 108 cm.setPurpose("To implementers map between medical device codes and LOINC codes"); 109 cm.setCopyright("This content LOINC \u00ae is copyright \u00a9 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at http://loinc.org/terms-of-use"); 110 cm.setSource(new UriType("http://loinc.org/vs")); 111 cm.setTarget(new UriType(MDC_ALL_VALUES)); 112 ConceptMapGroupComponent g = cm.addGroup(); 113 g.setSource("urn:iso:std:iso:11073:10101"); 114 g.setTarget("http://loinc.org"); 115 116 CSVReader csv = new CSVReader(ManagedFileAccess.inStream(src)); 117 csv.readHeaders(); 118 while (csv.line()) { 119 SourceElementComponent e = g.addElement(); 120 e.setCode(csv.cell("IEEE_CF_CODE10")); 121 e.setDisplay(csv.cell("IEEE_DESCRIPTION")); 122 TargetElementComponent t = e.addTarget(); 123 t.setEquivalence(ConceptMapEquivalence.EQUIVALENT); 124 t.setCode(csv.cell("LOINC_NUM")); 125 t.setDisplay(csv.cell("LOINC_LONG_COMMON_NAME")); 126 } 127 new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path(dst, "conceptmap-" + cm.getId() + ".xml")), cm); 128 System.out.println("Done"); 129 return cm; 130 } 131 132 public static CodeSystem generateMDC(String src, String dst, UcumService ucum) throws IOException, FHIRException { 133 CSVReader csv = new CSVReader(ManagedFileAccess.inStream(src)); 134 csv.readHeaders(); 135 CodeSystem cs = new CodeSystem(); 136 Map<String, String> ucumIssues = new HashMap<String, String>(); 137 138 int errorCount = 0; 139 cs.setId("MDC"); 140 cs.setUrl("urn:iso:std:iso:11073:10101"); 141 cs.setVersion("[todo]"); 142 cs.setName("11073:10101 codes for the FHIR community"); 143 cs.setStatus(PublicationStatus.ACTIVE); 144 cs.setExperimental(false); 145 cs.setDateElement(new DateTimeType()); 146 cs.setPublisher("HL7 (FHIR Project)"); 147 ContactDetail cd = cs.addContact(); 148 ContactPoint cp = cd.addTelecom(); 149 cp.setSystem(ContactPointSystem.URL); 150 cp.setValue("http://ieee?"); 151 cs.setDescription("1073 Codes for the FHIR community (generated from the Rosetta data"); 152 Identifier i = new Identifier(); 153 cs.setIdentifier(i); 154 i.setSystem("urn:ietf:rfc:3986"); 155 i.setValue("urn:oid:2.16.840.1.113883.6.24"); 156 cs.setCaseSensitive(false); 157 cs.setContent(CodeSystemContentMode.COMPLETE); 158 cs.addProperty().setCode("ucum").setDescription("UCUM units associated with Concept").setType(PropertyType.STRING); 159 cs.addProperty().setCode("unit").setDescription("MDC units associated with Concept").setType(PropertyType.STRING); 160 cs.addProperty().setCode("refid").setDescription("MDC Reference Id for Concept").setType(PropertyType.CODE); 161 Set<String> codes = new HashSet<String>(); 162 while (csv.line()) { 163 if (csv.has("CF_CODE10")) { 164 String code = csv.cell("CF_CODE10"); 165 if (codes.contains(code)) 166 System.out.println("Duplicate Code " + code); 167 else { 168 codes.add(code); 169 ConceptDefinitionComponent c = cs.addConcept(); 170 c.setCode(code); 171 c.setDisplay(csv.cell("Common Term")); 172 c.setDefinition(csv.cell("Term Description")); 173 String vd = csv.cell("Vendor_Description"); 174 if (!c.hasDefinition()) 175 c.setDefinition(vd); 176 if (!c.hasDisplay()) 177 c.setDisplay(vd); 178 String refid = csv.cell("REFID"); 179 c.addProperty().setCode("refid").setValue(new CodeType().setValue(refid)); 180 if (csv.has("Synonym")) 181 c.addDesignation().setValue(csv.cell("Synonym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("synonym")); 182 if (csv.has("Acronym")) 183 c.addDesignation().setValue(csv.cell("Acronym")).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setDisplay("acronym")); 184 if (csv.has("Systematic Name")) { 185 String sysName = csv.cell("Systematic Name"); 186 if (!c.hasDefinition()) 187 c.setDefinition(sysName); 188 c.addDesignation().setValue(sysName).setUse(new Coding().setSystem("http://hl7.org/fhir/designation-use").setCode("structured-name")); 189 } 190 if (csv.has("UOM_MDC")) 191 c.addProperty().setCode("unit").setValue(new StringType().setValue(csv.cell("UOM_MDC"))); 192 if (csv.has("UOM_UCUM")) { 193 CommaSeparatedStringBuilder ul = new CommaSeparatedStringBuilder(); 194 for (String u : csv.cell("UOM_UCUM").split(" ")) { 195 String msg = ucum.validate(u); 196 if (msg != null) { 197 errorCount++; 198 ucumIssues.put(u, msg); 199 } else 200 ul.append(u); 201 } 202 if (ul.length() > 0) 203 c.addProperty().setCode("ucum").setValue(new StringType().setValue(ul.toString())); 204 } 205 } 206 } 207 } 208 csv.close(); 209 new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(Utilities.path(dst, "codesystem-" + cs.getId() + ".xml")), cs); 210 System.out.println(errorCount + "UCUM errors"); 211 212 for (String u : sorted(ucumIssues.keySet())) 213 System.out.println("Invalid UCUM code: " + u + " because " + ucumIssues.get(u)); 214 215 return cs; 216 } 217 218 private static List<String> sorted(Set<String> keySet) { 219 List<String> names = new ArrayList<>(); 220 names.addAll(keySet); 221 Collections.sort(names); 222 return names; 223 } 224 225 226}