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