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