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; 071 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(new FileInputStream(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(new FileOutputStream(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(new FileInputStream(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(new FileOutputStream(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}