001package org.hl7.fhir.convertors.misc.argonaut; 002 003import java.io.ByteArrayOutputStream; 004import java.io.File; 005import java.io.FileInputStream; 006import java.io.IOException; 007import java.util.ArrayList; 008import java.util.Collections; 009import java.util.HashMap; 010import java.util.HashSet; 011import java.util.List; 012import java.util.Map; 013import java.util.Set; 014 015/* 016 Copyright (c) 2011+, HL7, Inc. 017 All rights reserved. 018 019 Redistribution and use in source and binary forms, with or without modification, 020 are permitted provided that the following conditions are met: 021 022 * Redistributions of source code must retain the above copyright notice, this 023 list of conditions and the following disclaimer. 024 * Redistributions in binary form must reproduce the above copyright notice, 025 this list of conditions and the following disclaimer in the documentation 026 and/or other materials provided with the distribution. 027 * Neither the name of HL7 nor the names of its contributors may be used to 028 endorse or promote products derived from this software without specific 029 prior written permission. 030 031 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 032 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 033 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 034 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 035 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 036 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 037 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 038 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 039 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 040 POSSIBILITY OF SUCH DAMAGE. 041 042 */ 043 044 045import org.apache.commons.io.IOUtils; 046import org.fhir.ucum.UcumEssenceService; 047import org.fhir.ucum.UcumService; 048import org.hl7.fhir.convertors.misc.CDAUtilities; 049import org.hl7.fhir.convertors.misc.Convert; 050import org.hl7.fhir.convertors.misc.ConverterBase; 051import org.hl7.fhir.convertors.misc.ccda.CcdaExtensions; 052import org.hl7.fhir.dstu3.context.SimpleWorkerContext; 053import org.hl7.fhir.dstu3.formats.IParser.OutputStyle; 054import org.hl7.fhir.dstu3.formats.JsonParser; 055import org.hl7.fhir.dstu3.formats.XmlParser; 056import org.hl7.fhir.dstu3.model.Address; 057import org.hl7.fhir.dstu3.model.AllergyIntolerance; 058import org.hl7.fhir.dstu3.model.AllergyIntolerance.AllergyIntoleranceReactionComponent; 059import org.hl7.fhir.dstu3.model.Base; 060import org.hl7.fhir.dstu3.model.Binary; 061import org.hl7.fhir.dstu3.model.BooleanType; 062import org.hl7.fhir.dstu3.model.CodeableConcept; 063import org.hl7.fhir.dstu3.model.Coding; 064import org.hl7.fhir.dstu3.model.Condition; 065import org.hl7.fhir.dstu3.model.Condition.ConditionVerificationStatus; 066import org.hl7.fhir.dstu3.model.ContactPoint; 067import org.hl7.fhir.dstu3.model.DocumentReference; 068import org.hl7.fhir.dstu3.model.DocumentReference.DocumentReferenceContentComponent; 069import org.hl7.fhir.dstu3.model.DocumentReference.DocumentReferenceContextComponent; 070import org.hl7.fhir.dstu3.model.DomainResource; 071import org.hl7.fhir.dstu3.model.Dosage; 072import org.hl7.fhir.dstu3.model.Encounter; 073import org.hl7.fhir.dstu3.model.Encounter.EncounterHospitalizationComponent; 074import org.hl7.fhir.dstu3.model.Encounter.EncounterStatus; 075import org.hl7.fhir.dstu3.model.Enumerations.DocumentReferenceStatus; 076import org.hl7.fhir.dstu3.model.Extension; 077import org.hl7.fhir.dstu3.model.Factory; 078import org.hl7.fhir.dstu3.model.HumanName; 079import org.hl7.fhir.dstu3.model.Identifier; 080import org.hl7.fhir.dstu3.model.Immunization; 081import org.hl7.fhir.dstu3.model.Immunization.ImmunizationExplanationComponent; 082import org.hl7.fhir.dstu3.model.Immunization.ImmunizationStatus; 083import org.hl7.fhir.dstu3.model.InstantType; 084import org.hl7.fhir.dstu3.model.ListResource; 085import org.hl7.fhir.dstu3.model.ListResource.ListMode; 086import org.hl7.fhir.dstu3.model.ListResource.ListStatus; 087import org.hl7.fhir.dstu3.model.Location; 088import org.hl7.fhir.dstu3.model.Medication; 089import org.hl7.fhir.dstu3.model.MedicationStatement; 090import org.hl7.fhir.dstu3.model.MedicationStatement.MedicationStatementStatus; 091import org.hl7.fhir.dstu3.model.Narrative; 092import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus; 093import org.hl7.fhir.dstu3.model.Observation; 094import org.hl7.fhir.dstu3.model.Observation.ObservationRelationshipType; 095import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; 096import org.hl7.fhir.dstu3.model.Organization; 097import org.hl7.fhir.dstu3.model.Patient; 098import org.hl7.fhir.dstu3.model.Period; 099import org.hl7.fhir.dstu3.model.Practitioner; 100import org.hl7.fhir.dstu3.model.Procedure; 101import org.hl7.fhir.dstu3.model.Procedure.ProcedurePerformerComponent; 102import org.hl7.fhir.dstu3.model.Procedure.ProcedureStatus; 103import org.hl7.fhir.dstu3.model.Reference; 104import org.hl7.fhir.dstu3.model.Resource; 105import org.hl7.fhir.dstu3.model.StringType; 106import org.hl7.fhir.dstu3.model.StructureDefinition; 107import org.hl7.fhir.dstu3.model.Timing; 108import org.hl7.fhir.dstu3.model.Type; 109import org.hl7.fhir.dstu3.utils.NarrativeGenerator; 110import org.hl7.fhir.dstu3.utils.ResourceUtilities; 111import org.hl7.fhir.utilities.Utilities; 112import org.hl7.fhir.utilities.ZipGenerator; 113import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 114import org.hl7.fhir.utilities.validation.ValidationMessage; 115import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 116import org.hl7.fhir.utilities.xhtml.NodeType; 117import org.hl7.fhir.utilities.xhtml.XhtmlNode; 118import org.hl7.fhir.utilities.xml.XMLUtil; 119import org.w3c.dom.Element; 120 121public class ArgonautConverter extends ConverterBase { 122 // public final static String DEF_TS_SERVER = "http://fhir-dev.healthintersections.com.au/open"; 123 public final static String DEV_TS_SERVER = "http://local.fhir.org:8080/open"; 124 public static final String UCUM_PATH = "c:\\work\\org.hl7.fhir\\build\\implementations\\java\\org.hl7.fhir.convertors\\samples\\ucum-essence.xml"; 125 public static final String SRC_PATH = "c:\\work\\org.hl7.fhir\\build\\publish\\"; 126 private static final String DEFAULT_ID_SPACE = "urn:uuid:e8e06b15-0f74-4b8e-b5e2-609dae7119dc"; 127 128 private static final boolean WANT_SAVE = true; 129 private static final boolean WANT_VALIDATE = false; 130 private final UcumService ucumSvc; 131 // private ValidationEngine validator; 132 private final SimpleWorkerContext context; 133 private final Map<String, Map<String, Integer>> sections = new HashMap<>(); 134 private final Map<String, Practitioner> practitionerCache = new HashMap<>(); 135 private final Set<String> oids = new HashSet<>(); 136 private final Map<String, ZipGenerator> zipsX = new HashMap<>(); 137 private final Map<String, ZipGenerator> zipsJ = new HashMap<>(); 138 private final Map<String, Stats> stats = new HashMap<>(); 139 public int perfCount; 140 int errors = 0; 141 int warnings = 0; 142 Map<String, Integer> procCodes = new HashMap<>(); 143 Map<String, Integer> condCodes = new HashMap<>(); 144 Map<String, Integer> allergyCodes = new HashMap<>(); 145 private String destFolder; 146 private ZipGenerator zipJ; 147 private ZipGenerator zipX; 148 149 public ArgonautConverter(UcumService ucumSvc, String path) throws Exception { 150 super(); 151 this.ucumSvc = ucumSvc; 152 context = SimpleWorkerContext.fromPack(path); 153// validator = new ValidationEngine(); 154// validator.readDefinitions(path); 155// validator.setAnyExtensionsAllowed(true); 156 } 157 158 public static void main(String[] args) { 159 try { 160 ArgonautConverter c = new ArgonautConverter(new UcumEssenceService(UCUM_PATH), Utilities.path(SRC_PATH, "validation.xml.zip")); 161 c.destFolder = "C:\\work\\com.healthintersections.fhir\\argonaut\\fhir"; 162 c.convert("C:\\work\\com.healthintersections.fhir\\argonaut\\cda\\file_emergency", new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("EMER")); 163 c.convert("C:\\work\\com.healthintersections.fhir\\argonaut\\cda\\file_ed", new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("IMP")); 164 c.convert("C:\\work\\com.healthintersections.fhir\\argonaut\\cda\\fileX", new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("AMB")); 165 c.printSectionSummaries(); 166 c.closeZips(); 167 System.out.println("All done. " + c.getErrors() + " errors, " + c.getWarnings() + " warnings"); 168 } catch (Exception e) { 169 e.printStackTrace(); 170 } 171 } 172 173 public int getErrors() { 174 return errors; 175 } 176 177 public int getWarnings() { 178 return warnings; 179 } 180 181 public void convert(String sourceFolder, Coding clss) throws Exception { 182 File source = ManagedFileAccess.file(sourceFolder); 183 for (String f : source.list()) { 184 convert(sourceFolder, f, clss); 185 } 186 } 187 188 private void closeZips() throws Exception { 189 for (ZipGenerator z : zipsJ.values()) 190 z.close(); 191 for (ZipGenerator z : zipsX.values()) 192 z.close(); 193 } 194 195 public void printSectionSummaries() { 196 System.out.println("Statistics:"); 197 for (String n : sorted(stats.keySet())) { 198 Stats s = stats.get(n); 199 System.out.println(" " + n + ": generated " + s.getInstances() + ", errors " + s.getErrors() + ", warnings " + s.getWarnings()); 200 } 201 202 System.out.println("OIDs:"); 203 for (String n : sorted(oids)) 204 System.out.println(" " + n); 205 206 for (String n : sections.keySet()) { 207 System.out.println(n + " Analysis"); 208 Map<String, Integer> s = sections.get(n); 209 for (String p : sorted(s.keySet())) { 210 System.out.println(" " + p + ": " + s.get(p)); 211 } 212 } 213 214 dumpCodes(); 215 } 216 217 private List<String> sorted(Set<String> keys) { 218 List<String> names = new ArrayList<>(); 219 names.addAll(keys); 220 Collections.sort(names); 221 return names; 222 } 223 224 private void convert(String sourceFolder, String filename, Coding clss) throws IOException { 225 if (ManagedFileAccess.file(Utilities.path(sourceFolder, filename)).length() == 0) 226 return; 227 228 CDAUtilities cda; 229 try { 230 System.out.println("Process " + Utilities.path(sourceFolder, filename)); 231 cda = new CDAUtilities(ManagedFileAccess.inStream(Utilities.path(sourceFolder, filename))); 232 zipJ = new ZipGenerator(Utilities.path(destFolder, "json/doc", Utilities.changeFileExt(filename, ".json.zip"))); 233 zipX = new ZipGenerator(Utilities.path(destFolder, "xml/doc", Utilities.changeFileExt(filename, ".xml.zip"))); 234 Element doc = cda.getElement(); 235 Convert convert = new Convert(cda, ucumSvc, "-0400"); 236 convert.setGenerateMissingExtensions(true); 237 Context context = new Context(); 238 context.setBaseId(Utilities.changeFileExt(filename, "")); 239 context.setEncClass(clss); 240 makeSubject(cda, convert, doc, context, context.getBaseId() + "-patient"); 241 makeAuthor(cda, convert, doc, context, context.getBaseId() + "-author"); 242 makeEncounter(cda, convert, doc, context, context.getBaseId() + "-encounter"); 243 Element body = cda.getDescendent(doc, "component/structuredBody"); 244 for (Element c : cda.getChildren(body, "component")) { 245 processSection(cda, convert, context, cda.getChild(c, "section")); 246 } 247 oids.addAll(convert.getOids()); 248 saveResource(context.getEncounter()); 249 makeBinary(sourceFolder, filename, context); 250 makeDocumentReference(cda, convert, doc, context); 251 zipJ.close(); 252 zipX.close(); 253 } catch (Exception e) { 254 throw new Error("Unable to process " + Utilities.path(sourceFolder, filename) + ": " + e.getMessage(), e); 255 } 256 } 257 258 private void processSection(CDAUtilities cda, Convert convert, Context context, Element section) throws Exception { 259 checkNoSubject(cda, section, "Section"); 260 261 // this we do by templateId 262 if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.11") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.5.1")) 263 processProblemsSection(cda, convert, section, context); 264 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.12") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.7.1")) 265 processProcedureSection(cda, convert, section, context); 266 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.3") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.22.1")) 267 processEncountersSection(cda, convert, section, context); 268 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.6.1")) 269 processAllergiesSection(cda, convert, section, context); 270 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.2.1") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.6")) 271 processImmunizationsSection(cda, convert, section, context); 272 else if (cda.hasTemplateId(section, "1.3.6.1.4.1.19376.1.5.3.1.3.1")) 273 processReasonForEncounter(cda, convert, section, context); 274 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.3.1") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.14")) 275 processResultsSection(cda, convert, section, context); 276 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.4.1") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.16")) 277 processVitalSignsSection(cda, convert, section, context); 278 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.1.1") || cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.8")) 279 processMedicationsSection(cda, convert, section, context); 280 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.22.2.17") || cda.hasTemplateId(section, "2.16.840.1.113883.3.88.11.83.126")) 281 processSocialHistorySection(cda, convert, section, context); 282 else if (cda.hasTemplateId(section, "2.16.840.1.113883.10.20.1.9")) 283 scanSection("Payers", section); 284 else 285 throw new Exception("Unprocessed section " + cda.getChild(section, "title").getTextContent()); 286 } 287 288 private void checkNoSubject(CDAUtilities cda, Element act, String path) throws Exception { 289 if (cda.getChild(act, "subject") != null) 290 throw new Exception("The conversion program cannot accept a subject at the location " + path); 291 } 292 293 private void scanSection(String name, Element child) { 294 Map<String, Integer> section; 295 if (sections.containsKey(name)) 296 section = sections.get(name); 297 else { 298 section = new HashMap<>(); 299 sections.put(name, section); 300 } 301 iterateChildren(section, "/", child); 302 } 303 304 private void iterateChildren(Map<String, Integer> section, String path, Element element) { 305 Element child = XMLUtil.getFirstChild(element); 306 while (child != null) { 307 String pathC = path + child.getNodeName() + attributes(child); 308 if (section.containsKey(pathC)) 309 section.put(pathC, section.get(pathC) + 1); 310 else 311 section.put(pathC, 1); 312 iterateChildren(section, pathC + "/", child); 313 child = XMLUtil.getNextSibling(child); 314 } 315 } 316 317 private String attributes(Element child) { 318 String s = ","; 319 if (child.hasAttribute("inversionInd")) 320 s += "inversionInd:" + child.getAttribute("inversionInd") + ","; 321 if (child.hasAttribute("negationInd")) 322 s += "negationInd:" + child.getAttribute("negationInd") + ","; 323 if (child.hasAttribute("nullFlavor")) 324 s += "nullFlavor:" + child.getAttribute("nullFlavor") + ","; 325 if (child.hasAttribute("xsi:type")) 326 s += "type:" + child.getAttribute("xsi:type") + ","; 327 s = s.substring(0, s.length() - 1); 328 329 if (child.getNodeName().equals("statusCode")) 330 return "[code:" + child.getAttribute("code") + "]"; 331 if (child.getNodeName().equals("temnplateId")) 332 return "[id:" + child.getAttribute("root") + "]"; 333 else if (child.hasAttribute("moodCode")) 334 return "[" + child.getAttribute("classCode") + "," + child.getAttribute("moodCode") + s + "]"; 335 else if (child.hasAttribute("classCode")) 336 return "[" + child.getAttribute("classCode") + s + "]"; 337 else if (child.hasAttribute("typeCode")) 338 return "[" + child.getAttribute("typeCode") + s + "]"; 339 else if (Utilities.noString(s)) 340 return ""; 341 else 342 return "[" + s.substring(1) + "]"; 343 } 344 345 private void saveResource(Resource resource) throws Exception { 346 saveResource(resource, null); 347 } 348 349 private void saveResource(Resource resource, String extraType) throws Exception { 350 if (!WANT_SAVE) 351 return; 352 353 DomainResource dr = null; 354 if (resource instanceof DomainResource) { 355 dr = (DomainResource) resource; 356 if (!dr.hasText()) { 357 NarrativeGenerator generator = new NarrativeGenerator("", "", context); 358 generator.generate(dr); 359 } 360 } 361 XmlParser xparser = new XmlParser(); 362 xparser.setOutputStyle(OutputStyle.PRETTY); 363 JsonParser jparser = new JsonParser(); 364 jparser.setOutputStyle(OutputStyle.PRETTY); 365 366 ByteArrayOutputStream ba = new ByteArrayOutputStream(); 367 xparser.compose(ba, resource); 368 ba.close(); 369 byte[] srcX = ba.toByteArray(); 370 ba = new ByteArrayOutputStream(); 371 jparser.compose(ba, resource); 372 ba.close(); 373 byte[] srcJ = ba.toByteArray(); 374 375 String rn = resource.getResourceType().toString(); 376 if (extraType != null) 377 rn = rn + extraType; 378 zipX.addBytes(resource.getId() + ".xml", srcX, false); 379 zipJ.addBytes(resource.getId() + ".json", srcJ, false); 380 if (!zipsX.containsKey(rn)) { 381 zipsX.put(rn, new ZipGenerator(Utilities.path(destFolder, "xml/type", rn + ".xml.zip"))); 382 zipsJ.put(rn, new ZipGenerator(Utilities.path(destFolder, "json/type", rn + ".json.zip"))); 383 stats.put(rn, new Stats()); 384 } 385 386 zipsJ.get(rn).addBytes(resource.getId() + ".json", srcJ, false); 387 zipsX.get(rn).addBytes(resource.getId() + ".xml", srcX, false); 388 Stats ss = stats.get(rn); 389 ss.setInstances(ss.getInstances() + 1); 390 391 String profile = resource.getUserString("profile"); 392 validate(srcX, profile, resource, ss); 393 } 394 395 private void validate(byte[] src, String url, Resource resource, Stats stats) throws Exception { 396 if (!WANT_VALIDATE) 397 return; 398 if (url == null) 399 url = "http://hl7.org/fhir/StructureDefinition/" + resource.getResourceType().toString(); 400 StructureDefinition def = context.fetchResource(StructureDefinition.class, url); 401 if (def == null) 402 throw new Exception("Unable to find Structure Definition " + url); 403 404// validator.reset(); 405// validator.setProfile(def); 406// validator.setSource(src); 407// validator.process(); 408 List<ValidationMessage> msgs = null; // validator.getOutputs(); 409 boolean ok = false; 410 boolean first = true; 411 for (ValidationMessage m : msgs) { 412 if (m.getLevel() == IssueSeverity.ERROR && !msgOk(m.getMessage())) { 413 if (first) { 414 System.out.println(" validate " + resource.getId() + ".xml against " + url); 415 first = false; 416 } 417 System.out.println(" " + m.getLevel().toCode() + ": " + m.getMessage() + " @ " + m.getLocation()); 418 if (m.getLevel() == IssueSeverity.WARNING) { 419 stats.setWarnings(stats.getWarnings() + 1); 420 warnings++; 421 } 422 if (m.getLevel() == IssueSeverity.ERROR || m.getLevel() == IssueSeverity.FATAL) { 423 stats.setErrors(stats.getErrors() + 1); 424 errors++; 425 } 426 } 427 428 ok = ok && !(m.getLevel() == IssueSeverity.ERROR || m.getLevel() == IssueSeverity.FATAL); 429 } 430 } 431 432 private boolean msgOk(String message) { 433 return message.equals("Invalid Resource target type. Found Observation, but expected one of (DiagnosticReport)"); 434 } 435 436 private void checkGenerateIdentifier(List<Identifier> ids, DomainResource resource) { 437 if (ids.isEmpty()) 438 ids.add(new Identifier().setSystem(DEFAULT_ID_SPACE).setValue(resource.getClass().getName().toLowerCase() + "-" + resource.getId())); 439 } 440 441 private void makeSubject(CDAUtilities cda, Convert convert, Element doc, Context context, String id) throws Exception { 442 Element rt = cda.getChild(doc, "recordTarget"); 443 scanSection("Patient", rt); 444 Element pr = cda.getChild(rt, "patientRole"); 445 Element p = cda.getChild(pr, "patient"); 446 447 Patient pat = new Patient(); 448 pat.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/patient-daf-dafpatient"); 449 StringBuilder b = new StringBuilder(); 450 451 pat.setId(id); 452 for (Element e : cda.getChildren(p, "name")) { 453 HumanName name = convert.makeNameFromEN(e); 454 pat.getName().add(name); 455 b.append(NarrativeGenerator.displayHumanName(name)); 456 b.append(" "); 457 } 458 b.append("("); 459 for (Element e : cda.getChildren(pr, "id")) { 460 Identifier identifier = convert.makeIdentifierFromII(e); 461 pat.getIdentifier().add(identifier); 462 b.append(identifier.getValue()); 463 b.append(", "); 464 } 465 466 for (Element e : cda.getChildren(pr, "addr")) 467 pat.getAddress().add(makeDefaultAddress(convert.makeAddressFromAD(e))); 468 for (Element e : cda.getChildren(pr, "telecom")) 469 pat.getTelecom().add(convert.makeContactFromTEL(e)); 470 pat.setGender(convert.makeGenderFromCD(cda.getChild(p, "administrativeGenderCode"))); 471 b.append(pat.getGender().getDisplay()); 472 b.append(", "); 473 pat.setBirthDateElement(convert.makeDateFromTS(cda.getChild(p, "birthTime"))); 474 b.append("DOB: "); 475 b.append(pat.getBirthDateElement().toHumanDisplay()); 476 b.append(")"); 477 pat.setMaritalStatus(convert.makeCodeableConceptFromCD(cda.getChild(p, "maritalStatusCode"))); 478 479 pat.addExtension(Factory.newExtension(CcdaExtensions.DAF_NAME_RACE, convert.makeCodeableConceptFromCD(cda.getChild(p, "raceCode")), false)); 480 pat.addExtension(Factory.newExtension(CcdaExtensions.DAF_NAME_ETHNICITY, convert.makeCodeableConceptFromCD(cda.getChild(p, "ethnicGroupCode")), false)); 481 482 pat.addExtension(Factory.newExtension(CcdaExtensions.NAME_RELIGION, convert.makeCodeableConceptFromCD(cda.getChild(p, "religiousAffiliationCode")), false)); 483 pat.addExtension(Factory.newExtension(CcdaExtensions.NAME_BIRTHPLACE, convert.makeAddressFromAD(cda.getChild(p, new String[]{"birthplace", "place", "addr"})), false)); 484 485 Element g = cda.getChild(p, "guardian"); 486 if (g != null) { 487 Patient.ContactComponent guardian = new Patient.ContactComponent(); 488 pat.getContact().add(guardian); 489 guardian.getRelationship().add(Factory.newCodeableConcept("GUARD", "urn:oid:2.16.840.1.113883.5.110", "guardian")); 490 for (Element e : cda.getChildren(g, "addr")) 491 if (guardian.getAddress() == null) 492 guardian.setAddress(makeDefaultAddress(convert.makeAddressFromAD(e))); 493 for (Element e : cda.getChildren(g, "telecom")) 494 guardian.getTelecom().add(convert.makeContactFromTEL(e)); 495 g = cda.getChild(g, "guardianPerson"); 496 for (Element e : cda.getChildren(g, "name")) 497 if (guardian.getName() == null) 498 guardian.setName(convert.makeNameFromEN(e)); 499 } 500 501 Element l = cda.getChild(p, "languageCommunication"); 502 CodeableConcept cc = new CodeableConcept(); 503 Coding c = new Coding(); 504 c.setSystem(ResourceUtilities.FHIR_LANGUAGE); 505 c.setCode(patchLanguage(cda.getChild(l, "languageCode").getAttribute("code"))); 506 cc.getCoding().add(c); 507 pat.addCommunication().setLanguage(cc); 508 509 Element prv = cda.getChild(pr, "providerOrganization"); 510 if (prv != null) 511 pat.setManagingOrganization(new Reference().setReference("Organization/" + processOrganization(prv, cda, convert, context).getId())); 512 513 context.setSubjectRef(new Reference().setDisplay(b.toString()).setReference("Patient/" + pat.getId())); 514 saveResource(pat); 515 } 516 517 private Organization processOrganization(Element oo, CDAUtilities cda, Convert convert, Context context) throws Exception { 518 Organization org = new Organization(); 519 org.setId(context.getBaseId() + "-organization-" + context.getOrgId()); 520 org.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/org-daf-daforganization"); 521 context.setOrgId(context.getOrgId() + 1); 522 for (Element e : cda.getChildren(oo, "id")) 523 org.getIdentifier().add(convert.makeIdentifierFromII(e)); 524 for (Element e : cda.getChildren(oo, "addr")) 525 org.getAddress().add(makeDefaultAddress(convert.makeAddressFromAD(e))); 526 for (Element e : cda.getChildren(oo, "telecom")) { 527 ContactPoint cp = convert.makeContactFromTEL(e); 528 if (Utilities.noString(cp.getValue())) 529 cp.setValue("1 (555) 555 5555"); 530 org.getTelecom().add(cp); 531 } 532 for (Element e : cda.getChildren(oo, "name")) 533 org.setName(e.getTextContent()); 534 saveResource(org); 535 return org; 536 } 537 538 private Address makeDefaultAddress(Address ad) { 539 if (ad == null || ad.isEmpty()) { 540 ad = new Address(); 541 ad.addLine("21 Doar road"); 542 ad.setCity("Erewhon"); 543 ad.setState("CA"); 544 ad.setPostalCode("31233"); 545 } 546 return ad; 547 } 548 549 private String patchLanguage(String lang) { 550 if (lang.equals("spa")) 551 return "es"; 552 if (lang.equals("eng")) 553 return "en"; 554 return lang; 555 } 556 557 ///legalAuthenticator/assignedEntity: 2979 558 ///legalAuthenticator/assignedEntity/addr: 2979 559 ///legalAuthenticator/assignedEntity/assignedPerson: 2979 560 ///legalAuthenticator/assignedEntity/id: 2979 561 ///legalAuthenticator/assignedEntity/representedOrganization: 2979 562 ///legalAuthenticator/assignedEntity/representedOrganization/addr: 2979 563 ///legalAuthenticator/assignedEntity/representedOrganization/id: 2979 564 ///legalAuthenticator/assignedEntity/representedOrganization/name: 2979 565 ///legalAuthenticator/assignedEntity/representedOrganization/telecom: 2979 566 ///legalAuthenticator/assignedEntity/telecom: 2979 567 568 private Practitioner makeAuthor(CDAUtilities cda, Convert convert, Element doc, Context context, String id) throws Exception { 569 Element a = cda.getChild(doc, "author"); 570 scanSection("Author", a); 571 Practitioner author = processPerformer(cda, convert, context, a, "assignedAuthor", "assignedPerson"); 572 context.setAuthorRef(new Reference().setDisplay(author.getUserString("display")).setReference("Practitioner/" + author.getId())); 573 return author; 574 } 575 576 private Practitioner makePerformer(CDAUtilities cda, Convert convert, Context context, Element eperf, String roleName, String entityName) throws Exception { 577 Element ae = cda.getChild(eperf, roleName); 578 Element ap = cda.getChild(ae, entityName); 579 580 StringBuilder b = new StringBuilder(); 581 582 Practitioner perf = new Practitioner(); 583 perf.setId("performer-" + perfCount); 584 perf.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/pract-daf-dafpract"); 585 perfCount++; 586 for (Element e : cda.getChildren(ae, "id")) { 587 Identifier id = convert.makeIdentifierFromII(e); 588 perf.getIdentifier().add(id); 589 } 590 591 for (Element e : cda.getChildren(ap, "name")) { 592 HumanName name = convert.makeNameFromEN(e); 593 perf.addName(name); 594 b.append(NarrativeGenerator.displayHumanName(name)); 595 b.append(" "); 596 } 597 for (Element e : cda.getChildren(ae, "addr")) 598 perf.getAddress().add(makeDefaultAddress(convert.makeAddressFromAD(e))); 599 boolean first = true; 600 for (Element e : cda.getChildren(ae, "telecom")) { 601 ContactPoint contact = convert.makeContactFromTEL(e); 602 perf.getTelecom().add(contact); 603 if (!Utilities.noString(contact.getValue())) { 604 if (first) { 605 b.append("("); 606 first = false; 607 } else 608 b.append(" "); 609 b.append(NarrativeGenerator.displayContactPoint(contact)); 610 } 611 } 612 if (!first) 613 b.append(")"); 614 615// Element e = cda.getChild(ae, "representedOrganization"); 616// if (e != null) 617// perf.addRole().setOrganization(new Reference().setReference("Organization/"+processOrganization(e, cda, convert, context).getId())); 618 perf.setUserData("display", b.toString()); 619 return perf; 620 } 621 622 ///serviceEvent/performer/functionCode: 9036 623 private Encounter makeEncounter(CDAUtilities cda, Convert convert, Element doc, Context context, String id) throws Exception { 624 Element co = cda.getChild(doc, "componentOf"); 625 Element ee = cda.getChild(co, "encompassingEncounter"); 626 scanSection("Encounter", co); 627 Element of = cda.getChild(doc, "documentationOf"); 628 Element se = cda.getChild(of, "serviceEvent"); 629 scanSection("Encounter", of); 630 631 Encounter enc = new Encounter(); 632 enc.setId(id); 633 enc.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/encounter-daf-dafencounter"); 634 context.setEncounter(enc); 635 enc.setSubject(context.getSubjectRef()); 636 637 for (Element e : cda.getChildren(ee, "id")) 638 enc.getIdentifier().add(convert.makeIdentifierFromII(e)); 639 checkGenerateIdentifier(enc.getIdentifier(), enc); 640 641 Period p1 = convert.makePeriodFromIVL(cda.getChild(ee, "effectiveTime")); 642 // Period p2 = convert.makePeriodFromIVL(cda.getChild(se, "effectiveTime")); // well, what is this? 643 // if (!Base.compareDeep(p1, p2, false)) 644 // throw new Error("episode time mismatch: "+NarrativeGenerator.displayPeriod(p1)+" & "+NarrativeGenerator.displayPeriod(p2)); 645 enc.setPeriod(p1); 646 if (p1.hasEnd()) 647 enc.setStatus(EncounterStatus.FINISHED); 648 else 649 enc.setStatus(EncounterStatus.INPROGRESS); 650 enc.setClass_(context.getEncClass()); 651 652 Element dd = cda.getChild(ee, "dischargeDispositionCode"); 653 if (dd != null) { 654 enc.setHospitalization(new EncounterHospitalizationComponent()); 655 enc.getHospitalization().setDischargeDisposition(convert.makeCodeableConceptFromCD(dd)); 656 } 657 for (Element e : cda.getChildren(se, "performer")) { 658 Practitioner p = processPerformer(cda, convert, context, e, "assignedEntity", "assignedPerson"); 659 Reference ref = new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display")); 660 if (ref != null) 661 enc.addParticipant().setIndividual(ref); 662 } 663 return enc; 664 } 665 666 private Practitioner processPerformer(CDAUtilities cda, Convert convert, Context context, Element e, String roleName, String entityName) throws Exception { 667 Practitioner perf = makePerformer(cda, convert, context, e, roleName, entityName); 668 if (perf == null) 669 return null; 670 671 Reference ref = null; 672 for (Identifier identifier : perf.getIdentifier()) { 673 String key = keyFor(identifier); 674 if (practitionerCache.containsKey(key)) 675 return practitionerCache.get(key); 676 } 677 678 saveResource(perf); 679 for (Identifier identifier : perf.getIdentifier()) { 680 String key = "Practitioner-" + keyFor(identifier); 681 practitionerCache.put(key, perf); 682 } 683 return perf; 684 } 685 686 private String keyFor(Identifier identifier) { 687 return identifier.getSystem() + "||" + identifier.getValue(); 688 } 689 690 private void buildNarrative(DomainResource resource, Element child) { 691 if (!Utilities.noString(child.getTextContent())) { 692 XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); 693 String s = child.getTextContent().trim(); 694 if (Utilities.noString(s)) 695 div.addText("No Narrative provided in the source CDA document"); 696 else 697 div.addText(s); 698 resource.setText(new Narrative().setStatus(NarrativeStatus.ADDITIONAL).setDiv(div)); 699 } 700 } 701 702 private void processProcedureSection(CDAUtilities cda, Convert convert, Element sect, Context context) throws Exception { 703 scanSection("Procedures", sect); 704 ListResource list = new ListResource(); 705 list.setId(context.getBaseId() + "-list-procedures"); 706 // list.setUserData("profile", "") none? 707 list.setSubject(context.getSubjectRef()); 708 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(sect, "code")), null)); 709 list.setTitle(cda.getChild(sect, "title").getTextContent()); 710 list.setStatus(ListStatus.CURRENT); 711 list.setMode(ListMode.SNAPSHOT); 712 list.setDateElement(context.getNow()); 713 list.setSource(context.getAuthorRef()); 714 buildNarrative(list, cda.getChild(sect, "text")); 715 716 int i = 0; 717 for (Element c : cda.getChildren(sect, "entry")) { 718 Element p = cda.getChild(c, "procedure"); 719 Procedure proc = new Procedure(); 720 proc.setId(context.getBaseId() + "-procedure-" + i); 721 proc.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/procedure-daf-dafprocedure"); 722 i++; 723 proc.setSubject(context.getSubjectRef()); 724 proc.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 725 list.addEntry().setItem(new Reference().setReference("Procedure/" + proc.getId())); 726 proc.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(p, "code")), null)); 727 recordProcedureCode(proc.getCode()); 728 for (Element e : cda.getChildren(p, "id")) 729 proc.getIdentifier().add(convert.makeIdentifierFromII(e)); 730 731 proc.setStatus(determineProcedureStatus(cda.getChild(p, "statusCode"))); 732 buildNarrative(proc, cda.getChild(p, "text")); 733 proc.setPerformed(convert.makeDateTimeFromTS(cda.getChild(p, "effectiveTime"))); 734 735 for (Element e : cda.getChildren(p, "performer")) { 736 ProcedurePerformerComponent part = proc.addPerformer(); 737 Practitioner pp = processPerformer(cda, convert, context, e, "assignedEntity", "assignedPerson"); 738 Reference ref = new Reference().setReference("Practitioner/" + pp.getId()).setDisplay(pp.getUserString("display")); 739 part.setActor(ref); 740 } 741 saveResource(proc); 742 } 743 saveResource(list); 744 } 745 746 private CodeableConcept inspectCode(CodeableConcept cc, Coding def) { 747 if (cc != null) { 748 for (Coding c : cc.getCoding()) { 749 if ("http://snomed.info/sct".equals(c.getSystem())) { 750 if ("ASSERTION".equals(c.getCode())) 751 c.setSystem("http://hl7.org/fhir/v3/ActCode"); 752 } 753 if ("http://hl7.org/fhir/v3/ActCode".equals(c.getSystem()) && "ASSERTION".equals(c.getCode())) { 754 if (def == null) 755 throw new Error("need a default code"); 756 c.setSystem(def.getSystem()); 757 c.setVersion(def.getVersion()); 758 c.setCode(def.getCode()); 759 c.setDisplay(def.getDisplay()); 760 } 761 } 762 } 763 return cc; 764 } 765 766 private ProcedureStatus determineProcedureStatus(Element child) { 767 if ("completed".equals(child.getAttribute("code"))) 768 return ProcedureStatus.COMPLETED; 769 throw new Error("not done yet: " + child.getAttribute("code")); 770 } 771 772 private void processReasonForEncounter(CDAUtilities cda, Convert convert, Element sect, Context context) throws Exception { 773 scanSection("Reason", sect); 774 context.getEncounter().addReason().setText(cda.getChild(sect, "text").getTextContent()); 775 } 776 777 private void processProblemsSection(CDAUtilities cda, Convert convert, Element sect, Context context) throws Exception { 778 scanSection("Problems", sect); 779 ListResource list = new ListResource(); 780 list.setId(context.getBaseId() + "-list-problems"); 781 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafproblemlist"); 782 list.setSubject(context.getSubjectRef()); 783 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(sect, "code")), null)); 784 list.setTitle(cda.getChild(sect, "title").getTextContent()); 785 list.setStatus(ListStatus.CURRENT); 786 list.setMode(ListMode.SNAPSHOT); 787 list.setDateElement(context.getNow()); 788 list.setSource(context.getAuthorRef()); 789 buildNarrative(list, cda.getChild(sect, "text")); 790 791 int i = 0; 792 for (Element c : cda.getChildren(sect, "entry")) { 793 Element pca = cda.getChild(c, "act"); // problem concern act 794 Condition cond = new Condition(); 795 cond.setId(context.getBaseId() + "-problem-" + i); 796 cond.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/condition-daf-dafcondition"); 797 i++; 798 cond.setSubject(context.getSubjectRef()); 799 cond.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 800 cond.setVerificationStatus(getVerificationStatusFromAct(cda.getChild(pca, "statusCode"))); 801 802 cond.setAssertedDateElement(convert.makeDateTimeFromTS(cda.getChild(cda.getChild(pca, "effectiveTime"), "low"))); 803 804 boolean found = false; 805 for (Element e : cda.getChildren(pca, "id")) { 806 Identifier id = convert.makeIdentifierFromII(e); 807 cond.getIdentifier().add(id); 808 } 809 if (!found) { 810 list.addEntry().setItem(new Reference().setReference("Condition/" + cond.getId())); 811 for (Element e : cda.getChildren(pca, "performer")) { 812 if (cond.hasAsserter()) 813 throw new Error("additional asserter discovered"); 814 Practitioner p = processPerformer(cda, convert, context, e, "assignedEntity", "assignedPerson"); 815 Reference ref = new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display")); 816 cond.setAsserter(ref); 817 } 818 Element po = cda.getChild(cda.getChild(pca, "entryRelationship"), "observation"); // problem observation 819 cond.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(po, "value")), null)); 820 recordConditionCode(cond.getCode()); 821 cond.setOnset(convert.makeDateTimeFromTS(cda.getChild(cda.getChild(po, "effectiveTime"), "low"))); 822 Element pso = cda.getChild(cda.getChild(po, "entryRelationship"), "observation"); // problem status observation 823 String status = cda.getChild(pso, "value").getAttribute("code"); 824 if (status.equals("55561003")) 825 cond.setAbatement(new BooleanType("false")); 826 else 827 throw new Error("unknown status code " + status); 828 saveResource(cond); 829 } 830 } 831 saveResource(list); 832 } 833 834 private ConditionVerificationStatus getVerificationStatusFromAct(Element child) { 835 String s = child.getAttribute("code"); 836 if (!"active".equals(s)) 837 System.out.println(s); 838 return ConditionVerificationStatus.CONFIRMED; 839 } 840 841 private void processAllergiesSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 842 scanSection("Allergies", section); 843 ListResource list = new ListResource(); 844 list.setId(context.getBaseId() + "-list-allergies"); 845 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafallergylist"); 846 list.setSubject(context.getSubjectRef()); 847 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 848 list.setTitle(cda.getChild(section, "title").getTextContent()); 849 list.setStatus(ListStatus.CURRENT); 850 list.setDateElement(context.getNow()); 851 list.setSource(context.getAuthorRef()); 852 list.setMode(ListMode.SNAPSHOT); 853 buildNarrative(list, cda.getChild(section, "text")); 854 855 int i = 0; 856 for (Element c : cda.getChildren(section, "entry")) { 857 Element apa = cda.getChild(c, "act"); // allergy problem act 858 AllergyIntolerance ai = new AllergyIntolerance(); 859 ai.setId(context.getBaseId() + "-allergy-" + i); 860 ai.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/allergyintolerance-daf-dafallergyintolerance"); 861 i++; 862 ai.setPatient(context.getSubjectRef()); 863 864 ai.setAssertedDateElement(convert.makeDateTimeFromTS(cda.getChild(cda.getChild(apa, "effectiveTime"), "low"))); 865 boolean found = false; 866 for (Element e : cda.getChildren(apa, "id")) { 867 Identifier id = convert.makeIdentifierFromII(e); 868 ai.getIdentifier().add(id); 869 } 870 if (!found) { 871 list.addEntry().setItem(new Reference().setReference("AllergyIntolerance/" + ai.getId())); 872 873 Element ao = cda.getChild(cda.getChild(apa, "entryRelationship"), "observation"); // allergy observation 874 if (!cda.getChild(ao, "value").getAttribute("code").equals("419511003")) 875 throw new Error("unexpected code"); 876 // nothing.... 877 878 // no allergy status observation 879 List<Element> reactions = cda.getChildren(ao, "entryRelationship"); 880 Element pe = cda.getChild(cda.getChild(cda.getChild(ao, "participant"), "participantRole"), "playingEntity"); 881 Element pec = cda.getChild(pe, "code"); 882 if (pec == null || !Utilities.noString(pec.getAttribute("nullFlavor"))) { 883 String n = cda.getChild(pe, "name").getTextContent(); 884 // if (n.contains("No Known Drug Allergies") && reactions.isEmpty()) 885 // ai.setSubstance(new CodeableConcept().setText(n)); // todo: what do with this? 886 // else 887 ai.setCode(new CodeableConcept().setText(n)); 888 } else 889 ai.setCode(inspectCode(convert.makeCodeableConceptFromCD(pec), null)); 890 recordAllergyCode(ai.getCode()); 891 if (!reactions.isEmpty()) { 892 AllergyIntoleranceReactionComponent aie = ai.addReaction(); 893 for (Element er : reactions) { 894 Element ro = cda.getChild(er, "observation"); 895 aie.addManifestation(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(ro, "value")), null)); 896 } 897 } 898 899 saveResource(ai); 900 } 901 } 902 saveResource(list); 903 } 904 905 private void processVitalSignsSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 906 scanSection("Vital Signs", section); 907 ListResource list = new ListResource(); 908 list.setId(context.getBaseId() + "-list-vitalsigns"); 909 //. list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafproblemlist"); no list 910 list.setSubject(context.getSubjectRef()); 911 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 912 list.setTitle(cda.getChild(section, "title").getTextContent()); 913 list.setStatus(ListStatus.CURRENT); 914 list.setMode(ListMode.SNAPSHOT); 915 list.setDateElement(context.getNow()); 916 list.setSource(context.getAuthorRef()); 917 buildNarrative(list, cda.getChild(section, "text")); 918 919 int i = 0; 920 for (Element c : cda.getChildren(section, "entry")) { 921 Element org = cda.getChild(c, "organizer"); // problem concern act 922 for (Element oc : cda.getChildren(org, "component")) { 923 Element o = cda.getChild(oc, "observation"); // problem concern act 924 Observation obs = new Observation(); 925 obs.setId(context.getBaseId() + "-vitals-" + i); 926 obs.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-vitalsigns-dafvitalsigns"); 927 i++; 928 obs.setSubject(context.getSubjectRef()); 929 obs.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 930 obs.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(o, "code")), null)); 931 932 boolean found = false; 933 for (Element e : cda.getChildren(o, "id")) { 934 Identifier id = convert.makeIdentifierFromII(e); 935 obs.getIdentifier().add(id); 936 } 937 938 if (!found) { 939 list.addEntry().setItem(new Reference().setReference("Observation/" + obs.getId())); 940 obs.setStatus(ObservationStatus.FINAL); 941 obs.setEffective(convert.makeDateTimeFromTS(cda.getChild(o, "effectiveTime"))); 942 String v = cda.getChild(o, "value").getAttribute("value"); 943 if (!Utilities.isDecimal(v, true)) { 944 obs.setDataAbsentReason(inspectCode(new CodeableConcept().setText(v), null)); 945 } else 946 obs.setValue(convert.makeQuantityFromPQ(cda.getChild(o, "value"))); 947 saveResource(obs, "-vs"); 948 } 949 } 950 } 951 saveResource(list, "-vs"); 952 } 953 954 private void processResultsSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 955 scanSection("Results", section); 956 957 ListResource list = new ListResource(); 958 list.setId(context.getBaseId() + "-list-results"); 959 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafresultlist"); 960 list.setSubject(context.getSubjectRef()); 961 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 962 list.setTitle(cda.getChild(section, "title").getTextContent()); 963 list.setStatus(ListStatus.CURRENT); 964 list.setMode(ListMode.SNAPSHOT); 965 list.setDateElement(context.getNow()); 966 list.setSource(context.getAuthorRef()); 967 buildNarrative(list, cda.getChild(section, "text")); 968 969 context.setObsId(0); 970 for (Element c : cda.getChildren(section, "entry")) { 971 Element org = cda.getChild(c, "organizer"); 972 if (org != null) { 973 Observation panel = new Observation(); 974 panel.setId(context.getBaseId() + "-results-" + context.getObsId()); 975 panel.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-results-dafresultobspanel"); 976 context.setObsId(context.getObsId() + 1); 977 panel.setSubject(context.getSubjectRef()); 978 panel.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 979 panel.setStatus(ObservationStatus.FINAL); 980 boolean found = false; 981 for (Element e : cda.getChildren(org, "id")) { 982 Identifier id = convert.makeIdentifierFromII(e); 983 panel.getIdentifier().add(id); 984 } 985 if (!found) { 986 list.addEntry().setItem(new Reference().setReference("Observation/" + panel.getId())); 987 988 panel.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(org, "code")), null)); 989 for (Element comp : cda.getChildren(org, "component")) { 990 Observation obs = processObservation(cda, convert, context, cda.getChild(comp, "observation")); 991 panel.addRelated().setType(ObservationRelationshipType.HASMEMBER).setTarget(new Reference().setReference("Observation/" + obs.getId())); 992 if (!panel.hasEffective()) 993 panel.setEffective(obs.getEffective()); 994 else { 995 if (!Base.compareDeep(panel.getEffective(), obs.getEffective(), false)) { 996 Period p = panel.getEffective() instanceof Period ? panel.getEffectivePeriod() : new Period().setStartElement(panel.getEffectiveDateTimeType()).setEndElement(panel.getEffectiveDateTimeType()); 997 if (p.getStartElement().after(obs.getEffectiveDateTimeType())) 998 p.setStartElement(obs.getEffectiveDateTimeType()); 999 if (p.getEndElement().before(obs.getEffectiveDateTimeType())) 1000 p.setEndElement(obs.getEffectiveDateTimeType()); 1001 panel.setEffective(p); 1002 } 1003 } 1004 1005 } 1006 saveResource(panel, "-res"); 1007 } 1008 } 1009 Element o = cda.getChild(c, "observation"); 1010 if (o != null) { 1011 Observation obs = processObservation(cda, convert, context, o); 1012 list.addEntry().setItem(new Reference().setReference("Observation/" + obs.getId())); 1013 } 1014 } 1015 saveResource(list, "-res"); 1016 } 1017 1018 private Observation processObservation(CDAUtilities cda, Convert convert, Context context, Element o) throws Exception { 1019 Observation obs = new Observation(); 1020 obs.setId(context.getBaseId() + "-results-" + context.getObsId()); 1021 context.setObsId(context.getObsId() + 1); 1022 obs.setSubject(context.getSubjectRef()); 1023 obs.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 1024 obs.setStatus(ObservationStatus.FINAL); 1025 obs.setEffective(convert.makeDateTimeFromTS(cda.getChild(o, "effectiveTime"))); 1026 obs.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(o, "code")), null)); 1027 obs.setInterpretation(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(o, "interpretationCode")), null)); 1028 Element rr = cda.getChild(o, "referenceRange"); 1029 if (rr != null) 1030 obs.addReferenceRange().setText(cda.getChild(cda.getChild(rr, "observationRange"), "text").getTextContent()); 1031 1032 Element v = cda.getChild(o, "value"); 1033 String type = v.getAttribute("xsi:type"); 1034 if ("ST".equals(type)) { 1035 obs.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-results-dafresultobsother"); 1036 obs.setValue(new StringType(v.getTextContent())); 1037 } else if ("CD".equals(type)) { 1038 obs.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-results-dafresultobscode"); 1039 obs.setValue(inspectCode(convert.makeCodeableConceptFromCD(v), null)); 1040 } else if ("PQ".equals(type)) { 1041 obs.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-results-dafresultobsquantity"); 1042 String va = cda.getChild(o, "value").getAttribute("value"); 1043 if (!Utilities.isDecimal(va, true)) { 1044 obs.setDataAbsentReason(inspectCode(new CodeableConcept().setText(va), null)); 1045 } else 1046 obs.setValue(convert.makeQuantityFromPQ(cda.getChild(o, "value"), null)); 1047 } else 1048 throw new Exception("Unknown type '" + type + "'"); 1049 1050 for (Element e : cda.getChildren(o, "id")) { 1051 Identifier id = convert.makeIdentifierFromII(e); 1052 obs.getIdentifier().add(id); 1053 } 1054 saveResource(obs, "-gen"); 1055 return obs; 1056 } 1057 1058 private void processSocialHistorySection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 1059 scanSection("Social History", section); 1060 int i = 0; 1061 for (Element c : cda.getChildren(section, "entry")) { 1062 Element o = cda.getChild(c, "observation"); 1063 Observation obs = new Observation(); 1064 obs.setId(context.getBaseId() + "-smoking-" + (i == 0 ? "" : Integer.toString(i))); 1065 obs.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/observation-daf-smokingstatus-dafsmokingstatus"); 1066 i++; 1067 obs.setSubject(context.getSubjectRef()); 1068 obs.setContext(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 1069 obs.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(o, "code")), new Coding().setSystem("http://loinc.org").setCode("72166-2"))); 1070 1071 boolean found = false; 1072 for (Element e : cda.getChildren(o, "id")) { 1073 Identifier id = convert.makeIdentifierFromII(e); 1074 obs.getIdentifier().add(convert.makeIdentifierFromII(e)); 1075 } 1076 if (!found) { 1077 obs.setStatus(ObservationStatus.FINAL); 1078 obs.setEffective(convert.makeDateTimeFromTS(cda.getChild(o, "effectiveTime"))); 1079 obs.setValue(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(o, "value")), null)); 1080 saveResource(obs, "-sh"); 1081 } 1082 } 1083 } 1084 1085 private void processMedicationsSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 1086 scanSection("Medications", section); 1087 ListResource list = new ListResource(); 1088 list.setId(context.getBaseId() + "-list-medications"); 1089 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafmedicationlist"); 1090 list.setSubject(context.getSubjectRef()); 1091 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 1092 list.setTitle(cda.getChild(section, "title").getTextContent()); 1093 list.setStatus(ListStatus.CURRENT); 1094 list.setMode(ListMode.SNAPSHOT); 1095 list.setDateElement(context.getNow()); 1096 list.setSource(context.getAuthorRef()); 1097 buildNarrative(list, cda.getChild(section, "text")); 1098 1099 int i = 0; 1100 for (Element c : cda.getChildren(section, "entry")) { 1101 Element sa = cda.getChild(c, "substanceAdministration"); // allergy problem act 1102 MedicationStatement ms = new MedicationStatement(); 1103 ms.setId(context.getBaseId() + "-medication-" + i); 1104 ms.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/medicationstatement-daf-dafmedicationstatement"); 1105 i++; 1106 ms.setSubject(context.getSubjectRef()); 1107 1108 boolean found = false; 1109 for (Element e : cda.getChildren(sa, "id")) { 1110 Identifier id = convert.makeIdentifierFromII(e); 1111 ms.getIdentifier().add(id); 1112 } 1113 if (!found) { 1114 ms.setStatus(MedicationStatementStatus.COMPLETED); 1115 list.addEntry().setItem(new Reference().setReference("MedicationStatement/" + ms.getId())); 1116 1117 Element mm = cda.getChild(cda.getChild(cda.getChild(sa, "consumable"), "manufacturedProduct"), "manufacturedMaterial"); // allergy observation 1118 ms.setMedication(new Reference().setReference("#med")); 1119 Medication med = new Medication(); 1120 med.setId("med"); 1121 med.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(mm, "code")), null)); 1122 ms.getContained().add(med); 1123 Dosage dosage = ms.addDosage(); 1124 Element qty = cda.getChild(sa, "doseQuantity"); // allergy observation 1125 try { 1126 if (cda.getChild(qty, "low") != null) { 1127 // todo: this is not correct? 1128 dosage.getExtension().add(new Extension().setUrl("http://healthintersections.com.au/fhir/extensions/medication-statement-range").setValue(convert.makeRangeFromIVLPQ(qty))); 1129 } else { 1130 dosage.setDose(convert.makeQuantityFromPQ(qty)); 1131 } 1132 } catch (Exception e) { 1133 System.out.println(" invalid dose quantity '" + qty.getAttribute("value") + " " + qty.getAttribute("unit") + "' (" + e.getClass().getName() + ") in " + context.getBaseId()); 1134 } 1135 dosage.setRoute(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(sa, "routeCode")), null)); 1136 Type t = convert.makeSomethingFromGTS(cda.getChildren(sa, "effectiveTime")); 1137 if (t instanceof Timing) { 1138 dosage.setTiming((Timing) t); 1139 if (dosage.getTiming().hasRepeat() && dosage.getTiming().getRepeat().hasBounds()) 1140 ms.setEffective(dosage.getTiming().getRepeat().getBounds()); 1141 } else if (t instanceof Period) 1142 ms.setEffective(t); 1143 else 1144 throw new Exception("Undecided how to handle " + t.getClass().getName()); 1145 1146 for (Element e : cda.getChildren(sa, "author")) { 1147 if (ms.hasInformationSource()) 1148 throw new Error("additional author discovered"); 1149 Practitioner p = processPerformer(cda, convert, context, e, "assignedAuthor", "assignedPerson"); 1150 Reference ref = new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display")); 1151 ms.setInformationSource(ref); 1152 ms.setDateAssertedElement(convert.makeDateTimeFromTS(cda.getChild(e, "time"))); 1153 } 1154 saveResource(ms); 1155 } 1156 } 1157 saveResource(list); 1158 } 1159 1160 private void processEncountersSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 1161 scanSection("Encounters", section); 1162 ListResource list = new ListResource(); 1163 list.setId(context.getBaseId() + "-list-encounters"); 1164 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafencounterlist"); 1165 list.setSubject(context.getSubjectRef()); 1166 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 1167 list.setTitle(cda.getChild(section, "title").getTextContent()); 1168 list.setStatus(ListStatus.CURRENT); 1169 list.setMode(ListMode.SNAPSHOT); 1170 list.setDateElement(context.getNow()); 1171 list.setSource(context.getAuthorRef()); 1172 buildNarrative(list, cda.getChild(section, "text")); 1173 1174 int i = 0; 1175 for (Element c : cda.getChildren(section, "entry")) { 1176 Element ee = cda.getChild(c, "encounter"); // allergy problem act 1177 Encounter enc = new Encounter(); 1178 enc.setId(context.getBaseId() + "-encounter-" + i); 1179 enc.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/encounter-daf-dafencounter"); 1180 i++; 1181 enc.setSubject(context.getSubjectRef()); 1182 list.addEntry().setItem(new Reference().setReference("Encounter/" + enc.getId())); 1183 1184 for (Element e : cda.getChildren(ee, "id")) 1185 enc.getIdentifier().add(convert.makeIdentifierFromII(e)); 1186 checkGenerateIdentifier(enc.getIdentifier(), enc); 1187 1188 1189 enc.setPeriod(convert.makePeriodFromIVL(cda.getChild(ee, "effectiveTime"))); 1190 if (enc.getPeriod().hasEnd()) 1191 enc.setStatus(EncounterStatus.FINISHED); 1192 else 1193 enc.setStatus(EncounterStatus.INPROGRESS); 1194 1195 if (cda.getChild(ee, "text") != null) 1196 enc.setClass_(convertTextToCoding(cda.getChild(ee, "text").getTextContent().trim())); 1197 else 1198 enc.setClass_(null); // todo: fix this 1199 1200 CodeableConcept type = inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(ee, "code")), null); 1201 enc.addType(type); 1202 1203 for (Element e : cda.getChildren(ee, "performer")) { 1204 Practitioner p = processPerformer(cda, convert, context, e, "assignedEntity", "assignedPerson"); 1205 Reference ref = new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display")); 1206 enc.addParticipant().setIndividual(ref).setPeriod(convert.makePeriodFromIVL(cda.getChild(e, "time"))); 1207 } 1208 enc.addLocation().setLocation(new Reference().setReference("#loc")); 1209 Location loc = new Location(); 1210 loc.setId("loc"); 1211 Element pr = cda.getChild(cda.getChild(ee, "participant"), "participantRole"); 1212 loc.setName(cda.getChild(cda.getChild(pr, "playingEntity"), "name").getTextContent()); 1213 loc.setType(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(pr, "code")), null)); 1214 enc.getContained().add(loc); 1215 saveResource(enc); 1216 } 1217 saveResource(list); 1218 } 1219 1220 private Coding convertTextToCoding(String v) { 1221 v = v.toLowerCase(); 1222 if (v.equals("inpatient")) 1223 return new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("IMP"); 1224 if (v.equals("emergency department") || v.equals("emergency department admit decision")) 1225 return new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("EMER"); 1226 if (v.equals("x-ray exam")) 1227 return new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("AMB"); 1228 if (v.equals("outpatient")) 1229 return new Coding().setSystem("http://hl7.org/fhir/v3/ActCode").setCode("AMB"); 1230 throw new Error("unknown encounter type " + v); 1231 } 1232 1233 private void processImmunizationsSection(CDAUtilities cda, Convert convert, Element section, Context context) throws Exception { 1234 scanSection("Immunizations", section); 1235 ListResource list = new ListResource(); 1236 list.setId(context.getBaseId() + "-list-immunizations"); 1237 list.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/list-daf-dafimmunizationlist"); 1238 list.setSubject(context.getSubjectRef()); 1239 list.setCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(section, "code")), null)); 1240 list.setTitle(cda.getChild(section, "title").getTextContent()); 1241 list.setStatus(ListStatus.CURRENT); 1242 list.setMode(ListMode.SNAPSHOT); 1243 list.setDateElement(context.getNow()); 1244 list.setSource(context.getAuthorRef()); 1245 buildNarrative(list, cda.getChild(section, "text")); 1246 1247 int i = 0; 1248 for (Element c : cda.getChildren(section, "entry")) { 1249 Element sa = cda.getChild(c, "substanceAdministration"); // allergy problem act 1250 Immunization imm = new Immunization(); 1251 imm.setId(context.getBaseId() + "-immunization-" + i); 1252 imm.setUserData("profile", "http://hl7.org/fhir/StructureDefinition/immunization-daf-dafimmunization"); 1253 i++; 1254 imm.setPatient(context.getSubjectRef()); 1255 imm.setEncounter(new Reference().setReference("Encounter/" + context.getEncounter().getId())); 1256 imm.setNotGiven("true".equals(sa.getAttribute("negationInd"))); 1257 imm.setStatus(convertImmunizationStatus(cda.getChild(sa, "statusCode"))); 1258 boolean found = false; 1259 for (Element e : cda.getChildren(sa, "id")) { 1260 Identifier id = convert.makeIdentifierFromII(e); 1261 imm.getIdentifier().add(id); 1262 } 1263 if (!found) { 1264 list.addEntry().setItem(new Reference().setReference("Immunization/" + imm.getId())); 1265 1266 imm.setDateElement(convert.makeDateTimeFromTS(cda.getChild(cda.getChild(sa, "effectiveTime"), "low"))); 1267 if (imm.getNotGiven()) { 1268 Element reason = cda.getChild(cda.getChildByAttribute(sa, "entryRelationship", "typeCode", "RSON"), "observation"); 1269 imm.setExplanation(new ImmunizationExplanationComponent()); 1270 imm.getExplanation().addReasonNotGiven(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(reason, "code")), null)); 1271 } 1272 Element mm = cda.getChild(cda.getChild(cda.getChild(sa, "consumable"), "manufacturedProduct"), "manufacturedMaterial"); 1273 imm.setVaccineCode(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(mm, "code")), null)); 1274 imm.setRoute(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(sa, "routeCode")), null)); 1275 if (cda.getChild(mm, "lotNumberText") != null) 1276 imm.setLotNumber(cda.getChild(mm, "lotNumberText").getTextContent()); 1277 Element mr = cda.getChild(cda.getChild(cda.getChild(sa, "consumable"), "manufacturedProduct"), "manufacturerOrganization"); 1278 if (mr != null) 1279 imm.setManufacturer(new Reference().setDisplay(cda.getChild(mr, "name").getTextContent())); 1280 1281 // the problem with this is that you can't have just a dose sequence number 1282 // Element subject = cda.getChild(cda.getChildByAttribute(sa, "entryRelationship", "typeCode", "SUBJ"), "observation"); 1283 // if (subject != null) 1284 // imm.addVaccinationProtocol().setDoseSequence(Integer.parseInt(cda.getChild(subject, "value").getAttribute("value"))); 1285 1286 boolean hasprf = false; 1287 for (Element e : cda.getChildren(sa, "performer")) { 1288 if (imm.hasPractitioner()) 1289 throw new Error("additional performer discovered"); 1290 Practitioner p = processPerformer(cda, convert, context, e, "assignedEntity", "assignedPerson"); 1291 Reference ref = new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display")); 1292 imm.addPractitioner().setActor(ref).setRole(new org.hl7.fhir.dstu3.model.CodeableConcept().addCoding(new Coding().setSystem("http://hl7.org/fhir/v2/0443").setCode("AP"))); 1293 hasprf = true; 1294 } 1295 imm.setPrimarySource(hasprf); 1296 saveResource(imm); 1297 } 1298 } 1299 saveResource(list); 1300 } 1301 1302 private ImmunizationStatus convertImmunizationStatus(Element child) { 1303 String s = child.getAttribute("code"); 1304 if (s.equals("completed")) 1305 return ImmunizationStatus.COMPLETED; 1306 throw new Error("Unexpected status " + s); 1307 } 1308 1309 // /informationRecipient: 2979 1310 // /informationRecipient/intendedRecipient: 2979 1311 // /informationRecipient/intendedRecipient/addr: 2979 1312 // /informationRecipient/intendedRecipient/informationRecipient: 2979 1313 // /informationRecipient/intendedRecipient/informationRecipient/name: 2979 1314 // /informationRecipient/intendedRecipient/receivedOrganization: 2979 1315 // /informationRecipient/intendedRecipient/receivedOrganization/addr: 2979 1316 // /informationRecipient/intendedRecipient/receivedOrganization/id: 2979 1317 // /informationRecipient/intendedRecipient/receivedOrganization/name: 2979 1318 // /informationRecipient/intendedRecipient/receivedOrganization/telecom: 2979 1319 1320 private void makeBinary(String sourceFolder, String filename, Context context) throws Exception { 1321 Binary binary = new Binary(); 1322 binary.setId(context.getBaseId() + "-binary"); 1323 binary.setContentType("application/hl7-v3+xml"); 1324 binary.setContent(IOUtils.toByteArray(ManagedFileAccess.inStream(Utilities.path(sourceFolder, filename)))); 1325 saveResource(binary); 1326 } 1327 1328 private void makeDocumentReference(CDAUtilities cda, Convert convert, Element doc, Context context) throws Exception { 1329 scanSection("document", doc); 1330 DocumentReference ref = new DocumentReference(); 1331 ref.setId(context.getBaseId() + "-document"); 1332 ref.setMasterIdentifier(convert.makeIdentifierFromII(cda.getChild(doc, "id"))); 1333 ref.setSubject(context.getSubjectRef()); 1334 ref.setType(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(doc, "code")), null)); 1335 ref.addAuthor(context.getAuthorRef()); 1336 ref.setCreatedElement(convert.makeDateTimeFromTS(cda.getChild(doc, "effectiveTime"))); 1337 ref.setIndexedElement(InstantType.now()); 1338 ref.setStatus(DocumentReferenceStatus.CURRENT); 1339 ref.addSecurityLabel(inspectCode(convert.makeCodeableConceptFromCD(cda.getChild(doc, "confidentialityCode")), null)); 1340 DocumentReferenceContentComponent cnt = ref.addContent(); 1341 cnt.getAttachment().setContentType("application/hl7-v3+xml").setUrl("Binary/" + context.getBaseId()).setLanguage(convertLanguage(cda.getChild(doc, "language"))); 1342 // for (Element ti : cda.getChildren(doc, "templateId")) 1343 // cnt.addFormat().setSystem("urn:oid:1.3.6.1.4.1.19376.1.2.3").setCode(value)("urn:oid:"+ti.getAttribute("root")); 1344 ref.setContext(new DocumentReferenceContextComponent()); 1345 ref.getContext().setPeriod(convert.makePeriodFromIVL(cda.getChild(cda.getChild(doc, "serviceEvent"), "effectiveTime"))); 1346 for (CodeableConcept cc : context.getEncounter().getType()) 1347 ref.getContext().addEvent(cc); 1348 ref.setDescription(cda.getChild(doc, "title").getTextContent()); 1349 ref.setCustodian(new Reference().setReference("Organization/" + processOrganization(cda.getDescendent(doc, "custodian/assignedCustodian/representedCustodianOrganization"), cda, convert, context).getId())); 1350 Practitioner p = processPerformer(cda, convert, context, cda.getChild(doc, "legalAuthenticator"), "assignedEntity", "assignedPerson"); 1351 ref.setAuthenticator(new Reference().setReference("Practitioner/" + p.getId()).setDisplay(p.getUserString("display"))); 1352 saveResource(ref); 1353 } 1354 1355 private String convertLanguage(Element child) { 1356 if (child == null) 1357 return null; 1358 return child.getAttribute("code"); 1359 } 1360 1361 private CodeableConcept makeClassCode(CodeableConcept type, DocumentReference ref) throws Exception { 1362 CodeableConcept res = new CodeableConcept(); 1363 String cs = type.getCoding().get(0).getCode(); 1364 if (cs.equals("18842-5") || cs.equals("34133-9")) 1365 return type; 1366 else if (cs.equals("34111-5")) { 1367 ref.getFormatCommentsPre().add("The underlying CDA document has the code '34111-5: Evaluation and Management Note' which is incorrect (wrong display/code combination). The type has been preserved even though it's wrong"); 1368 res.addCoding().setSystem("http://loinc.org").setCode("34109-9").setDisplay("Evaluation and management note"); 1369 } 1370 // else if (cs.equals("34111-5") || cs.equals("5666")) 1371 // res.addCoding().setSystem("http://loinc.org").setCode("LP173418-7").setDisplay("Note"); 1372 else 1373 throw new Exception("Uncategorised document type code: " + cs + ": " + type.getCoding().get(0).getDisplay()); 1374 return res; 1375 1376 } 1377 1378 private void recordProcedureCode(CodeableConcept code) { 1379 for (Coding c : code.getCoding()) { 1380 count(c, procCodes); 1381 } 1382 } 1383 1384 private void count(Coding c, Map<String, Integer> map) { 1385 String s = c.getSystem() + "::" + c.getCode(); 1386 if (map.containsKey(s)) 1387 map.put(s, map.get(s) + 1); 1388 else 1389 map.put(s, 1); 1390 } 1391 1392 private void recordConditionCode(CodeableConcept code) { 1393 for (Coding c : code.getCoding()) { 1394 count(c, condCodes); 1395 } 1396 } 1397 1398 private void recordAllergyCode(CodeableConcept code) { 1399 for (Coding c : code.getCoding()) { 1400 count(c, allergyCodes); 1401 } 1402 } 1403 1404 private void dumpCodes() { 1405 dump("Procedure Codes", procCodes); 1406 dump("Condition Codes", condCodes); 1407 dump("Allergy Codes", allergyCodes); 1408 } 1409 1410 private void dump(String string, Map<String, Integer> map) { 1411 System.out.println(string); 1412 System.out.println(); 1413 for (String s : map.keySet()) { 1414 System.out.println(s + ": " + map.get(s)); 1415 } 1416 System.out.println(); 1417 System.out.println(); 1418 } 1419 1420}