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