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