001package org.hl7.fhir.convertors.misc; 002 003 004 005 006 007import java.math.BigDecimal; 008import java.util.HashSet; 009import java.util.List; 010import java.util.Set; 011import java.util.UUID; 012 013/* 014 Copyright (c) 2011+, HL7, Inc. 015 All rights reserved. 016 017 Redistribution and use in source and binary forms, with or without modification, 018 are permitted provided that the following conditions are met: 019 020 * Redistributions of source code must retain the above copyright notice, this 021 list of conditions and the following disclaimer. 022 * Redistributions in binary form must reproduce the above copyright notice, 023 this list of conditions and the following disclaimer in the documentation 024 and/or other materials provided with the distribution. 025 * Neither the name of HL7 nor the names of its contributors may be used to 026 endorse or promote products derived from this software without specific 027 prior written permission. 028 029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 030 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 031 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 032 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 033 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 034 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 035 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 036 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 037 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 038 POSSIBILITY OF SUCH DAMAGE. 039 040*/ 041 042 043import org.fhir.ucum.UcumService; 044import org.hl7.fhir.dstu3.model.Address; 045import org.hl7.fhir.dstu3.model.Address.AddressUse; 046import org.hl7.fhir.dstu3.model.CodeableConcept; 047import org.hl7.fhir.dstu3.model.Coding; 048import org.hl7.fhir.dstu3.model.ContactPoint; 049import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem; 050import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointUse; 051import org.hl7.fhir.dstu3.model.DateTimeType; 052import org.hl7.fhir.dstu3.model.DateType; 053import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; 054import org.hl7.fhir.dstu3.model.Factory; 055import org.hl7.fhir.dstu3.model.HumanName; 056import org.hl7.fhir.dstu3.model.HumanName.NameUse; 057import org.hl7.fhir.dstu3.model.Identifier; 058import org.hl7.fhir.dstu3.model.InstantType; 059import org.hl7.fhir.dstu3.model.Period; 060import org.hl7.fhir.dstu3.model.Quantity; 061import org.hl7.fhir.dstu3.model.Range; 062import org.hl7.fhir.dstu3.model.SimpleQuantity; 063import org.hl7.fhir.dstu3.model.StringType; 064import org.hl7.fhir.dstu3.model.Timing; 065import org.hl7.fhir.dstu3.model.Timing.EventTiming; 066import org.hl7.fhir.dstu3.model.Timing.TimingRepeatComponent; 067import org.hl7.fhir.dstu3.model.Timing.UnitsOfTime; 068import org.hl7.fhir.dstu3.model.Type; 069import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 070import org.hl7.fhir.utilities.OIDUtils; 071import org.hl7.fhir.utilities.Utilities; 072import org.w3c.dom.Element; 073import org.w3c.dom.Node; 074 075public class Convert { 076 077 private final CDAUtilities cda; 078 private final UcumService ucumSvc; 079 private final Set<String> oids = new HashSet<String>(); 080 private final String defaultTimezone; 081 private boolean generateMissingExtensions; 082 083 public Convert(CDAUtilities cda, UcumService ucumSvc, String defaultTimezone) { 084 super(); 085 this.cda = cda; 086 this.ucumSvc = ucumSvc; 087 this.defaultTimezone = defaultTimezone; 088 } 089 090 public Identifier makeIdentifierFromII(Element e) throws Exception { 091 Identifier id = new Identifier(); 092 String r = e.getAttribute("root"); 093 String ex; 094 if (e.hasAttribute("extension") && Utilities.noString(e.getAttribute("extension"))) { 095 if (generateMissingExtensions) 096 ex = UUID.randomUUID().toString(); 097 else 098 throw new Exception("Broken identifier - extension is blank"); 099 } else 100 ex = e.getAttribute("extension"); 101 102 if (Utilities.noString(ex)) { 103 id.setSystem("urn:ietf:rfc:3986"); 104 if (isGuid(r)) 105 id.setValue("urn:uuid:" + r); 106 else if (UriForOid(r) != null) 107 id.setValue(UriForOid(r)); 108 else 109 id.setValue(UriForOid(r)); 110 } else { 111 if (isGuid(r)) 112 id.setSystem("urn:uuid:" + r); 113 else if (UriForOid(r) != null) 114 id.setSystem(UriForOid(r)); 115 else 116 id.setSystem("urn:oid:" + r); 117 id.setValue(ex); 118 } 119 return id; 120 } 121 122 public String makeURIfromII(Element e) { 123 String r = e.getAttribute("root"); 124 if (Utilities.noString(e.getAttribute("extension"))) { 125 if (isGuid(r)) 126 return "urn:uuid:" + r; 127 else if (UriForOid(r) != null) 128 return UriForOid(r); 129 else 130 return UriForOid(r); 131 } else { 132 if (isGuid(r)) 133 return "urn:uuid:" + r + "::" + e.getAttribute("extension"); 134 else if (UriForOid(r) != null) 135 return UriForOid(r) + "::" + e.getAttribute("extension"); 136 else 137 return "urn:oid:" + r + "::" + e.getAttribute("extension"); 138 } 139 } 140 141 private String UriForOid(String r) { 142 String uri = OIDUtils.getUriForOid(r); 143 if (uri != null) 144 return uri; 145 else { 146 oids.add(r); 147 return "urn:oid:" + r; 148 } 149 } 150 151 public boolean isGuid(String r) { 152 return r.matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"); 153 } 154 155 public InstantType makeInstantFromTS(Element child) throws Exception { 156 InstantType i = InstantType.parseV3(child.getAttribute("value")); 157 return i; 158 } 159 160 public CodeableConcept makeCodeableConceptFromCD(Element cv) throws Exception { 161 if (cv == null) 162 return null; 163 CodeableConcept cc = new CodeableConcept(); 164 cc.addCoding(makeCodingFromCV(cv)); 165 for (Element e : cda.getChildren(cv, "translation")) 166 cc.addCoding(makeCodingFromCV(e)); 167 if (cda.getChild(cv, "originalText") != null) { 168 Element ote = cda.getChild(cv, "originalText"); 169// if (cda.getChild(ote, "reference") != null) { 170// if (cda.getChild(ote, "reference").getAttribute("value").startsWith("#")) { 171// Element t = cda.getByXmlId(cda.getChild(ote, "reference").getAttribute("value").substring(1)); 172// String ot = t.getTextContent().trim(); 173// cc.setText(Utilities.noString(ot) ? null : ot); 174// } else 175// throw new Exception("external references not handled yet "+cda.getChild(ote, "reference").getAttribute("value")); 176// } else { 177 String ot = ote.getTextContent().trim(); 178 cc.setText(Utilities.noString(ot) ? null : ot); 179 //} 180 } 181 return cc; 182 } 183 184 public Coding makeCodingFromCV(Element cd) throws Exception { 185 if (cd == null || Utilities.noString(cd.getAttribute("code"))) 186 return null; 187 Coding c = new Coding(); 188 c.setCode(cd.getAttribute("code")); 189 c.setDisplay(cd.getAttribute("displayName")); 190 String r = cd.getAttribute("codeSystem"); 191 String uri = getUriForOID(r); 192 if (uri != null) 193 c.setSystem(uri); 194 else if (isGuid(r)) 195 c.setSystem("urn:uuid:" + r); 196 else if (UriForOid(r) != null) 197 c.setSystem(UriForOid(r)); 198 else 199 c.setSystem("urn:oid:" + r); 200 return c; 201 } 202 203 private String getUriForOID(String r) { 204 if (r.equals("2.16.840.1.113883.6.1")) 205 return "http://loinc.org"; 206 if (r.equals("2.16.840.1.113883.6.96")) 207 return "http://snomed.info/sct"; 208 return null; 209 } 210 211 public Address makeAddressFromAD(Element e) { 212 if (e == null) 213 return null; 214 Address a = new Address(); 215 String use = e.getAttribute("use"); 216 if (use != null) { 217 if (use.equals("H") || use.equals("HP") || use.equals("HV")) 218 a.setUse(AddressUse.HOME); 219 else if (use.equals("WP") || use.equals("DIR") || use.equals("PUB")) 220 a.setUse(AddressUse.WORK); 221 else if (use.equals("TMP")) 222 a.setUse(AddressUse.TEMP); 223 else if (use.equals("BAD")) 224 a.setUse(AddressUse.OLD); 225 } 226 Node n = e.getFirstChild(); 227 while (n != null) { 228 if (n.getNodeType() == Node.ELEMENT_NODE) { 229 String v = n.getTextContent(); 230 if (n.getLocalName().equals("additionalLocator")) 231 a.getLine().add(makeString(v)); 232// else if (e.getLocalName().equals("unitID")) 233// else if (e.getLocalName().equals("unitType")) 234 else if (n.getLocalName().equals("deliveryAddressLine")) 235 a.getLine().add(makeString(v)); 236// else if (e.getLocalName().equals("deliveryInstallationType")) 237// else if (e.getLocalName().equals("deliveryInstallationArea")) 238// else if (e.getLocalName().equals("deliveryInstallationQualifier")) 239// else if (e.getLocalName().equals("deliveryMode")) 240// else if (e.getLocalName().equals("deliveryModeIdentifier")) 241 else if (n.getLocalName().equals("streetAddressLine")) 242 a.getLine().add(makeString(v)); 243// else if (e.getLocalName().equals("houseNumber")) 244// else if (e.getLocalName().equals("buildingNumberSuffix")) 245// else if (e.getLocalName().equals("postBox")) 246// else if (e.getLocalName().equals("houseNumberNumeric")) 247// else if (e.getLocalName().equals("streetName")) 248// else if (e.getLocalName().equals("streetNameBase")) 249// else if (e.getLocalName().equals("streetNameType")) 250 else if (n.getLocalName().equals("direction")) 251 a.getLine().add(makeString(v)); 252 else if (n.getLocalName().equals("careOf")) 253 a.getLine().add(makeString(v)); 254// else if (e.getLocalName().equals("censusTract")) 255 else if (n.getLocalName().equals("country")) 256 a.setCountry(v); 257 //else if (e.getLocalName().equals("county")) 258 else if (n.getLocalName().equals("city")) 259 a.setCity(v); 260// else if (e.getLocalName().equals("delimiter")) 261// else if (e.getLocalName().equals("precinct")) 262 else if (n.getLocalName().equals("state")) 263 a.setState(v); 264 else if (n.getLocalName().equals("postalCode")) 265 a.setPostalCode(v); 266 } 267 n = n.getNextSibling(); 268 } 269 return a; 270 } 271 272 public StringType makeString(String v) { 273 StringType s = new StringType(); 274 s.setValue(v); 275 return s; 276 } 277 278 public ContactPoint makeContactFromTEL(Element e) throws Exception { 279 if (e == null) 280 return null; 281 if (e.hasAttribute("nullFlavor")) 282 return null; 283 ContactPoint c = new ContactPoint(); 284 String use = e.getAttribute("use"); 285 if (use != null) { 286 if (use.equals("H") || use.equals("HP") || use.equals("HV")) 287 c.setUse(ContactPointUse.HOME); 288 else if (use.equals("WP") || use.equals("DIR") || use.equals("PUB")) 289 c.setUse(ContactPointUse.WORK); 290 else if (use.equals("TMP")) 291 c.setUse(ContactPointUse.TEMP); 292 else if (use.equals("BAD")) 293 c.setUse(ContactPointUse.OLD); 294 } 295 if (e.getAttribute("value") != null) { 296 String[] url = e.getAttribute("value").split(":"); 297 if (url.length == 1) { 298 c.setValue(url[0].trim()); 299 c.setSystem(ContactPointSystem.PHONE); 300 } else { 301 if (url[0].equals("tel")) 302 c.setSystem(ContactPointSystem.PHONE); 303 else if (url[0].equals("mailto")) 304 c.setSystem(ContactPointSystem.EMAIL); 305 else if (e.getAttribute("value").contains(":")) 306 c.setSystem(ContactPointSystem.OTHER); 307 else 308 c.setSystem(ContactPointSystem.PHONE); 309 c.setValue(url[1].trim()); 310 } 311 } 312 return c; 313 314 } 315 316 public HumanName makeNameFromEN(Element e) { 317 if (e == null) 318 return null; 319 HumanName hn = new HumanName(); 320 String use = e.getAttribute("use"); 321 if (use != null) { 322 if (use.equals("L")) 323 hn.setUse(NameUse.USUAL); 324 else if (use.equals("C")) 325 hn.setUse(NameUse.OFFICIAL); 326 else if (use.equals("P") || use.equals("A")) 327 hn.setUse(NameUse.ANONYMOUS); 328 else if (use.equals("TMP")) 329 hn.setUse(NameUse.TEMP); 330 else if (use.equals("BAD")) 331 hn.setUse(NameUse.OLD); 332 } 333 334 Node n = e.getFirstChild(); 335 while (n != null) { 336 if (n.getNodeType() == Node.ELEMENT_NODE) { 337 String v = n.getTextContent(); 338 if (n.getLocalName().equals("family")) 339 hn.setFamilyElement(makeString(v)); 340 else if (n.getLocalName().equals("given")) 341 hn.getGiven().add(makeString(v)); 342 else if (n.getLocalName().equals("prefix")) 343 hn.getPrefix().add(makeString(v)); 344 else if (n.getLocalName().equals("suffix")) 345 hn.getSuffix().add(makeString(v)); 346 } 347 n = n.getNextSibling(); 348 } 349 return hn; 350 } 351 352 public DateTimeType makeDateTimeFromTS(Element ts) throws Exception { 353 if (ts == null) 354 return null; 355 356 String v = ts.getAttribute("value"); 357 if (Utilities.noString(v)) 358 return null; 359 360 if (v.length() > 8 && !hasTimezone(v)) 361 v += defaultTimezone; 362 DateTimeType d = DateTimeType.parseV3(v); 363 return d; 364 } 365 366 private boolean hasTimezone(String v) { 367 return v.contains("+") || v.contains("-") || v.endsWith("Z"); 368 } 369 370 371 public DateType makeDateFromTS(Element ts) throws Exception { 372 if (ts == null) 373 return null; 374 375 String v = ts.getAttribute("value"); 376 if (Utilities.noString(v)) 377 return null; 378 DateType d = DateType.parseV3(v); 379 return d; 380 } 381 382 public Period makePeriodFromIVL(Element ivl) throws Exception { 383 if (ivl == null) 384 return null; 385 Period p = new Period(); 386 Element low = cda.getChild(ivl, "low"); 387 if (low != null) 388 p.setStartElement(makeDateTimeFromTS(low)); 389 Element high = cda.getChild(ivl, "high"); 390 if (high != null) 391 p.setEndElement(makeDateTimeFromTS(high)); 392 393 if (p.getStartElement() != null || p.getEndElement() != null) 394 return p; 395 else 396 return null; 397 } 398 399 // this is a weird one - where CDA has an IVL, and FHIR has a date 400 public DateTimeType makeDateTimeFromIVL(Element ivl) throws Exception { 401 if (ivl == null) 402 return null; 403 if (ivl.hasAttribute("value")) 404 return makeDateTimeFromTS(ivl); 405 Element high = cda.getChild(ivl, "high"); 406 if (high != null) 407 return makeDateTimeFromTS(high); 408 Element low = cda.getChild(ivl, "low"); 409 if (low != null) 410 return makeDateTimeFromTS(low); 411 return null; 412 } 413 414 public Type makeStringFromED(Element e) throws Exception { 415 if (e == null) 416 return null; 417 if (cda.getChild(e, "reference") != null) { 418 if (cda.getChild(e, "reference").getAttribute("value").startsWith("#")) { 419 Element t = cda.getByXmlId(cda.getChild(e, "reference").getAttribute("value").substring(1)); 420 String ot = t.getTextContent().trim(); 421 return Utilities.noString(ot) ? null : Factory.newString_(ot); 422 } else 423 throw new Exception("external references not handled yet " + cda.getChild(e, "reference").getAttribute("value")); 424 } 425 return Factory.newString_(e.getTextContent()); 426 } 427 428 public Type makeTypeFromANY(Element e) throws Exception { 429 if (e == null) 430 return null; 431 String t = e.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "type"); 432 if (Utilities.noString(t)) 433 throw new Exception("Missing type on RIM attribute with type any"); 434 if (t.equals("CD") || t.equals("CE")) 435 return makeCodeableConceptFromCD(e); 436 else if (t.equals("ST")) 437 return makeStringFromED(e); 438 else 439 throw new Exception("Not done yet (type = " + t + ")"); 440 } 441 442 public Type makeMatchingTypeFromIVL(Element ivl) throws Exception { 443 if (ivl == null) 444 return null; 445 if (ivl.getAttribute("value") != null) 446 return makeDateTimeFromIVL(ivl); 447 if (cda.getChild(ivl, "low") != null || cda.getChild(ivl, "high") != null) 448 return makePeriodFromIVL(ivl); 449 throw new Exception("not handled yet"); 450 } 451 452 public Type makeCodeableConceptFromNullFlavor(String nf) throws Exception { 453 // Some nullFlavors have explicit values in value sets. This can only be called where there aren't. 454 if (nf == null || "".equals(nf)) 455 return null; 456 if ("NI".equals(nf)) 457 return null; // there's no code for this 458 if ("NA".equals(nf)) 459 return Factory.newCodeableConcept("unsupported", "http://hl7.org/fhir/data-absent-reason", "Unsupported"); // todo: is this reasonable? Why else would you use N/A? 460 if ("UNK".equals(nf)) 461 return Factory.newCodeableConcept("unknown", "http://hl7.org/fhir/data-absent-reason", "Unknown"); 462 if ("ASKU".equals(nf)) 463 return Factory.newCodeableConcept("asked", "http://hl7.org/fhir/data-absent-reason", "Asked/Unknown"); 464 if ("NAV".equals(nf)) 465 return Factory.newCodeableConcept("temp", "http://hl7.org/fhir/data-absent-reason", "Temporarily Unavailable"); 466 if ("NASK".equals(nf)) 467 return Factory.newCodeableConcept("notasked", "http://hl7.org/fhir/data-absent-reason", "Not Asked"); 468 if ("MSK".equals(nf)) 469 return Factory.newCodeableConcept("masked", "http://hl7.org/fhir/data-absent-reason", "Masked"); 470 if ("OTH".equals(nf)) 471 return null; // well, what should be done? 472 return null; // well, what should be done? 473 474 } 475 476 public Range makeRangeFromIVLPQ(Element ivlpq) throws Exception { 477 if (ivlpq == null) 478 return null; 479 Element low = cda.getChild(ivlpq, "low"); 480 Element high = cda.getChild(ivlpq, "high"); 481 if (low == null && high == null) 482 return null; 483 Range r = new Range(); 484 r.setLow(makeSimpleQuantityFromPQ(low, ivlpq.getAttribute("unit"))); 485 r.setHigh(makeSimpleQuantityFromPQ(high, ivlpq.getAttribute("unit"))); 486 return r; 487 } 488 489 public Quantity makeQuantityFromPQ(Element pq) throws Exception { 490 return makeQuantityFromPQ(pq, null); 491 } 492 493 public Quantity makeQuantityFromPQ(Element pq, String units) throws Exception { 494 if (pq == null) 495 return null; 496 Quantity qty = new Quantity(); 497 String n = pq.getAttribute("value").replace(",", "").trim(); 498 try { 499 qty.setValue(new BigDecimal(n)); 500 } catch (Exception e) { 501 throw new Exception("Unable to process value '" + n + "'", e); 502 } 503 units = Utilities.noString(pq.getAttribute("unit")) ? units : pq.getAttribute("unit"); 504 if (!Utilities.noString(units)) { 505 if (ucumSvc == null || ucumSvc.validate(units) != null) 506 qty.setUnit(units); 507 else { 508 qty.setCode(units); 509 qty.setSystem("http://unitsofmeasure.org"); 510 qty.setUnit(ucumSvc.getCommonDisplay(units)); 511 } 512 } 513 return qty; 514 } 515 516 public SimpleQuantity makeSimpleQuantityFromPQ(Element pq, String units) throws Exception { 517 if (pq == null) 518 return null; 519 SimpleQuantity qty = new SimpleQuantity(); 520 String n = pq.getAttribute("value").replace(",", "").trim(); 521 try { 522 qty.setValue(new BigDecimal(n)); 523 } catch (Exception e) { 524 throw new Exception("Unable to process value '" + n + "'", e); 525 } 526 units = Utilities.noString(pq.getAttribute("unit")) ? units : pq.getAttribute("unit"); 527 if (!Utilities.noString(units)) { 528 if (ucumSvc == null || ucumSvc.validate(units) != null) 529 qty.setUnit(units); 530 else { 531 qty.setCode(units); 532 qty.setSystem("http://unitsofmeasure.org"); 533 qty.setUnit(ucumSvc.getCommonDisplay(units)); 534 } 535 } 536 return qty; 537 } 538 539 public AdministrativeGender makeGenderFromCD(Element cd) throws Exception { 540 String code = cd.getAttribute("code"); 541 String system = cd.getAttribute("codeSystem"); 542 if ("2.16.840.1.113883.5.1".equals(system)) { 543 if ("F".equals(code)) 544 return AdministrativeGender.FEMALE; 545 if ("M".equals(code)) 546 return AdministrativeGender.MALE; 547 } 548 throw new Exception("Unable to read Gender " + system + "::" + code); 549 } 550 551 /* 552 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:EIVL_TS]: 389 553 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:EIVL_TS]/event: 389 554 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]: 33470 555 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/high: 20566 556 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/high[nullFlavor:NA]: 9581 557 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/low: 32501 558 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/low[nullFlavor:UNK]: 969 559 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:PIVL_TS]: 17911 560 /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:PIVL_TS]/period: 17911 561 */ 562 public Type makeSomethingFromGTS(List<Element> children) throws Exception { 563 if (children.isEmpty()) 564 return null; 565 if (children.size() == 1) { 566 String type = children.get(0).getAttribute("xsi:type"); 567 if (type.equals("IVL_TS")) 568 return makePeriodFromIVL(children.get(0)); 569 else 570 throw new Exception("Unknown GTS type '" + type + "'"); 571 } 572 CommaSeparatedStringBuilder t = new CommaSeparatedStringBuilder(); 573 for (Element c : children) 574 t.append(c.getAttribute("xsi:type")); 575 if (t.toString().equals("IVL_TS, PIVL_TS")) 576 return makeTimingFromBoundedPIVL(children.get(0), children.get(1)); 577 if (t.toString().equals("IVL_TS, EIVL_TS")) 578 return makeTimingFromBoundedEIVL(children.get(0), children.get(1)); 579 throw new Exception("Unknown GTS pattern '" + t + "'"); 580 } 581 582 private Type makeTimingFromBoundedEIVL(Element ivl, Element eivl) throws Exception { 583 Timing t = new Timing(); 584 t.setRepeat(new TimingRepeatComponent()); 585 Element e = cda.getChild(eivl, "event"); 586 t.getRepeat().setBounds(makePeriodFromIVL(ivl)); 587 t.getRepeat().addWhen(convertEventTiming(e.getAttribute("code"))); 588 return t; 589 } 590 591 private EventTiming convertEventTiming(String e) throws Exception { 592 if ("HS".equals(e)) 593 return EventTiming.HS; 594 throw new Exception("Unknown event " + e); 595 } 596 597 private Timing makeTimingFromBoundedPIVL(Element ivl, Element pivl) throws Exception { 598 Timing t = new Timing(); 599 t.setRepeat(new TimingRepeatComponent()); 600 Element p = cda.getChild(pivl, "period"); 601 t.getRepeat().setBounds(makePeriodFromIVL(ivl)); 602 t.getRepeat().setPeriod(new BigDecimal(p.getAttribute("value"))); 603 t.getRepeat().setPeriodUnit(convertTimeUnit(p.getAttribute("unit"))); 604 return t; 605 } 606 607 private UnitsOfTime convertTimeUnit(String u) throws Exception { 608 if ("h".equals(u)) 609 return UnitsOfTime.H; 610 if ("d".equals(u)) 611 return UnitsOfTime.D; 612 if ("w".equals(u)) 613 return UnitsOfTime.WK; 614 throw new Exception("Unknown unit of time " + u); 615 } 616 617 public Set<String> getOids() { 618 return oids; 619 } 620 621 public boolean isGenerateMissingExtensions() { 622 return generateMissingExtensions; 623 } 624 625 public void setGenerateMissingExtensions(boolean generateMissingExtensions) { 626 this.generateMissingExtensions = generateMissingExtensions; 627 } 628 629 630}