001package org.hl7.fhir.r4.elementmodel; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.Comparator; 035import java.util.HashMap; 036import java.util.HashSet; 037import java.util.List; 038import java.util.Map; 039import java.util.Set; 040 041import org.apache.commons.lang3.Validate; 042import org.hl7.fhir.exceptions.FHIRException; 043import org.hl7.fhir.r4.conformance.ProfileUtilities; 044import org.hl7.fhir.r4.model.Base; 045import org.hl7.fhir.r4.model.ElementDefinition; 046import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; 047import org.hl7.fhir.r4.model.Enumerations.BindingStrength; 048import org.hl7.fhir.r4.model.ICoding; 049import org.hl7.fhir.r4.model.StringType; 050import org.hl7.fhir.r4.model.StructureDefinition; 051import org.hl7.fhir.r4.model.Type; 052import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent; 053import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 054import org.hl7.fhir.utilities.ElementDecoration; 055import org.hl7.fhir.utilities.ElementDecoration.DecorationType; 056import org.hl7.fhir.utilities.Utilities; 057import org.hl7.fhir.utilities.xhtml.XhtmlNode; 058 059/** 060 * This class represents the underlying reference model of FHIR 061 * 062 * A resource is nothing but a set of elements, where every element has a name, 063 * maybe a stated type, maybe an id, and either a value or child elements (one 064 * or the other, but not both or neither) 065 * 066 * @author Grahame Grieve 067 * 068 */ 069public class Element extends Base { 070 071 public enum SpecialElement { 072 CONTAINED, BUNDLE_ENTRY, BUNDLE_OUTCOME, PARAMETER; 073 074 public static SpecialElement fromProperty(Property property) { 075 if (property.getStructure().getIdElement().getIdPart().equals("Parameters")) 076 return PARAMETER; 077 if (property.getStructure().getIdElement().getIdPart().equals("Bundle") && property.getName().equals("resource")) 078 return BUNDLE_ENTRY; 079 if (property.getStructure().getIdElement().getIdPart().equals("Bundle") && property.getName().equals("outcome")) 080 return BUNDLE_OUTCOME; 081 if (property.getName().equals("contained")) 082 return CONTAINED; 083 throw new Error("Unknown resource containing a native resource: " + property.getDefinition().getId()); 084 } 085 } 086 087 private List<String> comments;// not relevant for production, but useful in documentation 088 private String name; 089 private String type; 090 private String value; 091 private int index = -1; 092 private List<Element> children; 093 private Property property; 094 private Property elementProperty; // this is used when special is set to true - it tracks the underlying element 095 // property which is used in a few places 096 private int line; 097 private int col; 098 private SpecialElement special; 099 private XhtmlNode xhtml; // if this is populated, then value will also hold the string representation 100 private String explicitType; // for xsi:type attribute 101 102 public Element(String name) { 103 super(); 104 this.name = name; 105 } 106 107 public Element(Element other) { 108 super(); 109 name = other.name; 110 type = other.type; 111 property = other.property; 112 elementProperty = other.elementProperty; 113 special = other.special; 114 } 115 116 public Element(String name, Property property) { 117 super(); 118 this.name = name; 119 this.property = property; 120 } 121 122 public Element(String name, Property property, String type, String value) { 123 super(); 124 this.name = name; 125 this.property = property; 126 this.type = type; 127 this.value = value; 128 } 129 130 public void updateProperty(Property property, SpecialElement special, Property elementProperty) { 131 this.property = property; 132 this.elementProperty = elementProperty; 133 this.special = special; 134 } 135 136 public SpecialElement getSpecial() { 137 return special; 138 } 139 140 public String getName() { 141 return name; 142 } 143 144 public String getType() { 145 if (type == null) 146 return property.getType(name); 147 else 148 return type; 149 } 150 151 public String getValue() { 152 return value; 153 } 154 155 public boolean hasChildren() { 156 return !(children == null || children.isEmpty()); 157 } 158 159 public List<Element> getChildren() { 160 if (children == null) 161 children = new ArrayList<Element>(); 162 return children; 163 } 164 165 public boolean hasComments() { 166 return !(comments == null || comments.isEmpty()); 167 } 168 169 public List<String> getComments() { 170 if (comments == null) 171 comments = new ArrayList<String>(); 172 return comments; 173 } 174 175 public Property getProperty() { 176 return property; 177 } 178 179 public void setValue(String value) { 180 this.value = value; 181 } 182 183 public void setType(String type) { 184 this.type = type; 185 186 } 187 188 public boolean hasValue() { 189 return value != null; 190 } 191 192 public List<Element> getChildrenByName(String name) { 193 List<Element> res = new ArrayList<Element>(); 194 if (hasChildren()) { 195 for (Element child : children) 196 if (name.equals(child.getName())) 197 res.add(child); 198 } 199 return res; 200 } 201 202 public void numberChildren() { 203 if (children == null) 204 return; 205 206 String last = ""; 207 int index = 0; 208 for (Element child : children) { 209 if (child.getProperty().isList()) { 210 if (last.equals(child.getName())) { 211 index++; 212 } else { 213 last = child.getName(); 214 index = 0; 215 } 216 child.index = index; 217 } else { 218 child.index = -1; 219 } 220 child.numberChildren(); 221 } 222 } 223 224 public int getIndex() { 225 return index; 226 } 227 228 public boolean hasIndex() { 229 return index > -1; 230 } 231 232 public void setIndex(int index) { 233 this.index = index; 234 } 235 236 public String getChildValue(String name) { 237 if (children == null) 238 return null; 239 for (Element child : children) { 240 if (name.equals(child.getName())) 241 return child.getValue(); 242 } 243 return null; 244 } 245 246 public void setChildValue(String name, String value) { 247 if (children == null) 248 children = new ArrayList<Element>(); 249 for (Element child : children) { 250 if (name.equals(child.getName())) { 251 if (!child.isPrimitive()) 252 throw new Error("Cannot set a value of a non-primitive type (" + name + " on " + this.getName() + ")"); 253 child.setValue(value); 254 } 255 } 256 try { 257 setProperty(name.hashCode(), name, new StringType(value)); 258 } catch (FHIRException e) { 259 throw new Error(e); 260 } 261 } 262 263 public List<Element> getChildren(String name) { 264 List<Element> res = new ArrayList<Element>(); 265 if (children != null) 266 for (Element child : children) { 267 if (name.equals(child.getName())) 268 res.add(child); 269 } 270 return res; 271 } 272 273 public boolean hasType() { 274 if (type == null) 275 return property.hasType(name); 276 else 277 return true; 278 } 279 280 @Override 281 public String fhirType() { 282 return getType(); 283 } 284 285 @Override 286 public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException { 287 if (isPrimitive() && (hash == "value".hashCode()) && !Utilities.noString(value)) { 288// String tn = getType(); 289// throw new Error(tn+" not done yet"); 290 Base[] b = new Base[1]; 291 b[0] = new StringType(value); 292 return b; 293 } 294 295 List<Base> result = new ArrayList<Base>(); 296 if (children != null) { 297 for (Element child : children) { 298 if (child.getName().equals(name)) 299 result.add(child); 300 if (child.getName().startsWith(name) && child.getProperty().isChoice() 301 && child.getProperty().getName().equals(name + "[x]")) 302 result.add(child); 303 } 304 } 305 if (result.isEmpty() && checkValid) { 306// throw new FHIRException("not determined yet"); 307 } 308 return result.toArray(new Base[result.size()]); 309 } 310 311 @Override 312 protected void listChildren(List<org.hl7.fhir.r4.model.Property> childProps) { 313 if (children != null) { 314 Map<String, org.hl7.fhir.r4.model.Property> map = new HashMap<String, org.hl7.fhir.r4.model.Property>(); 315 for (Element c : children) { 316 org.hl7.fhir.r4.model.Property p = map.get(c.getName()); 317 if (p == null) { 318 p = new org.hl7.fhir.r4.model.Property(c.getName(), c.fhirType(), 319 c.getProperty().getDefinition().getDefinition(), c.getProperty().getDefinition().getMin(), 320 maxToInt(c.getProperty().getDefinition().getMax()), c); 321 childProps.add(p); 322 map.put(c.getName(), p); 323 324 } else 325 p.getValues().add(c); 326 } 327 } 328 } 329 330 @Override 331 public Base copy() { 332 Element element = new Element(this); 333 this.copyValues(element); 334 return element; 335 } 336 337 @Override 338 public void copyValues(Base dst) { 339 super.copyValues(dst); 340 341 Element dest = (Element) dst; 342 if (comments != null) { 343 dest.comments = new ArrayList<>(); 344 dest.comments.addAll(comments); 345 } else { 346 dest.comments = null; 347 } 348 dest.value = value; 349 if (children != null) { 350 dest.children = new ArrayList<>(); 351 for (Element child : children) { 352 dest.children.add((Element) child.copy()); 353 } 354 } else { 355 dest.children = null; 356 } 357 dest.line = line; 358 dest.col = col; 359 dest.xhtml = xhtml; 360 dest.explicitType = explicitType; 361 } 362 363 @Override 364 public Base setProperty(int hash, String name, Base value) throws FHIRException { 365 if ("xhtml".equals(getType()) && (hash == "value".hashCode())) { 366 this.xhtml = castToXhtml(value); 367 this.value = castToXhtmlString(value); 368 return this; 369 } 370 if (isPrimitive() && (hash == "value".hashCode())) { 371 this.value = castToString(value).asStringValue(); 372 return this; 373 } 374 375 if (!value.isPrimitive() && !(value instanceof Element)) { 376 if (isDataType(value)) 377 value = convertToElement(property.getChild(name), value); 378 else 379 throw new FHIRException("Cannot set property " + name + " on " + this.name 380 + " - value is not a primitive type (" + value.fhirType() + ") or an ElementModel type"); 381 } 382 383 if (children == null) 384 children = new ArrayList<Element>(); 385 Element childForValue = null; 386 387 // look through existing children 388 for (Element child : children) { 389 if (child.getName().equals(name)) { 390 if (!child.isList()) { 391 childForValue = child; 392 break; 393 } else { 394 Element ne = new Element(child); 395 children.add(ne); 396 numberChildren(); 397 childForValue = ne; 398 break; 399 } 400 } 401 } 402 403 int i = 0; 404 if (childForValue == null) 405 for (Property p : property.getChildProperties(this.name, type)) { 406 int t = -1; 407 for (int c = 0; c < children.size(); c++) { 408 Element e = children.get(c); 409 if (p.getName().equals(e.getName())) 410 t = c; 411 } 412 if (t > i) 413 i = t; 414 if (p.getName().equals(name) || p.getName().equals(name + "[x]")) { 415 Element ne = new Element(name, p); 416 children.add(i, ne); 417 childForValue = ne; 418 break; 419 } 420 } 421 422 if (childForValue == null) 423 throw new Error("Cannot set property " + name + " on " + this.name); 424 else if (value.isPrimitive()) { 425 if (childForValue.property.getName().endsWith("[x]")) 426 childForValue.name = name + Utilities.capitalize(value.fhirType()); 427 childForValue.setValue(value.primitiveValue()); 428 } else { 429 Element ve = (Element) value; 430 childForValue.type = ve.getType(); 431 if (childForValue.property.getName().endsWith("[x]")) 432 childForValue.name = name + Utilities.capitalize(childForValue.type); 433 else if (value.isResource()) { 434 if (childForValue.elementProperty == null) 435 childForValue.elementProperty = childForValue.property; 436 childForValue.property = ve.property; 437 childForValue.special = SpecialElement.BUNDLE_ENTRY; 438 } 439 if (ve.children != null) { 440 if (childForValue.children == null) 441 childForValue.children = new ArrayList<Element>(); 442 else 443 childForValue.children.clear(); 444 childForValue.children.addAll(ve.children); 445 } 446 } 447 return childForValue; 448 } 449 450 private Base convertToElement(Property prop, Base v) throws FHIRException { 451 return new ObjectConverter(property.getContext()).convert(prop, (Type) v); 452 } 453 454 private boolean isDataType(Base v) { 455 return v instanceof Type && property.getContext().getTypeNames().contains(v.fhirType()); 456 } 457 458 @Override 459 public Base makeProperty(int hash, String name) throws FHIRException { 460 if (isPrimitive() && (hash == "value".hashCode())) { 461 return new StringType(value); 462 } 463 464 if (children == null) 465 children = new ArrayList<Element>(); 466 467 // look through existing children 468 for (Element child : children) { 469 if (child.getName().equals(name)) { 470 if (!child.isList()) { 471 return child; 472 } else { 473 Element ne = new Element(child); 474 children.add(ne); 475 numberChildren(); 476 return ne; 477 } 478 } 479 } 480 481 for (Property p : property.getChildProperties(this.name, type)) { 482 if (p.getName().equals(name)) { 483 Element ne = new Element(name, p); 484 children.add(ne); 485 return ne; 486 } 487 } 488 489 throw new Error("Unrecognised name " + name + " on " + this.name); 490 } 491 492 private int maxToInt(String max) { 493 if (max.equals("*")) 494 return Integer.MAX_VALUE; 495 else 496 return Integer.parseInt(max); 497 } 498 499 @Override 500 public boolean isPrimitive() { 501 return type != null ? property.isPrimitive(type) : property.isPrimitive(property.getType(name)); 502 } 503 504 @Override 505 public boolean isBooleanPrimitive() { 506 return isPrimitive() && ("boolean".equals(type) || "boolean".equals(property.getType(name))); 507 } 508 509 @Override 510 public boolean isResource() { 511 return property.isResource(); 512 } 513 514 @Override 515 public boolean hasPrimitiveValue() { 516 return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name); 517 } 518 519 @Override 520 public String primitiveValue() { 521 if (isPrimitive()) 522 return value; 523 else { 524 if (hasPrimitiveValue() && children != null) { 525 for (Element c : children) { 526 if (c.getName().equals("value")) 527 return c.primitiveValue(); 528 } 529 } 530 return null; 531 } 532 } 533 534 // for the validator 535 public int line() { 536 return line; 537 } 538 539 public int col() { 540 return col; 541 } 542 543 public Element markLocation(int line, int col) { 544 this.line = line; 545 this.col = col; 546 return this; 547 } 548 549 public void clearDecorations() { 550 clearUserData("fhir.decorations"); 551 for (Element e : children) 552 e.clearDecorations(); 553 } 554 555 public void markValidation(StructureDefinition profile, ElementDefinition definition) { 556 @SuppressWarnings("unchecked") 557 List<ElementDecoration> decorations = (List<ElementDecoration>) getUserData("fhir.decorations"); 558 if (decorations == null) { 559 decorations = new ArrayList<>(); 560 setUserData("fhir.decorations", decorations); 561 } 562 decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getUserString("path"), definition.getPath())); 563 if (definition.getId() != null && tail(definition.getId()).contains(":")) { 564 String[] details = tail(definition.getId()).split(":"); 565 decorations.add(new ElementDecoration(DecorationType.SLICE, null, details[1])); 566 } 567 } 568 569 private String tail(String id) { 570 return id.contains(".") ? id.substring(id.lastIndexOf(".") + 1) : id; 571 } 572 573 public Element getNamedChild(String name) { 574 if (children == null) 575 return null; 576 Element result = null; 577 for (Element child : children) { 578 if (child.getName().equals(name)) { 579 if (result == null) 580 result = child; 581 else 582 throw new Error("Attempt to read a single element when there is more than one present (" + name + ")"); 583 } 584 } 585 return result; 586 } 587 588 public void getNamedChildren(String name, List<Element> list) { 589 if (children != null) 590 for (Element child : children) 591 if (child.getName().equals(name)) 592 list.add(child); 593 } 594 595 public String getNamedChildValue(String name) { 596 Element child = getNamedChild(name); 597 return child == null ? null : child.value; 598 } 599 600 public void getNamedChildrenWithWildcard(String string, List<Element> values) { 601 Validate.isTrue(string.endsWith("[x]")); 602 603 String start = string.substring(0, string.length() - 3); 604 if (children != null) { 605 for (Element child : children) { 606 if (child.getName().startsWith(start)) { 607 values.add(child); 608 } 609 } 610 } 611 } 612 613 public XhtmlNode getXhtml() { 614 return xhtml; 615 } 616 617 public Element setXhtml(XhtmlNode xhtml) { 618 this.xhtml = xhtml; 619 return this; 620 } 621 622 @Override 623 public boolean isEmpty() { 624 // GG: this used to also test !"".equals(value). 625 // the condition where "" is empty and there are no children is an error, and so 626 // this really only manifested as an issue in corner cases technical testing of 627 // the validator / FHIRPath. 628 // it should not cause any problems in real life. 629 if (value != null) { 630 return false; 631 } 632 for (Element next : getChildren()) { 633 if (!next.isEmpty()) { 634 return false; 635 } 636 } 637 return true; 638 } 639 640 public Property getElementProperty() { 641 return elementProperty; 642 } 643 644 public boolean hasElementProperty() { 645 return elementProperty != null; 646 } 647 648 public boolean hasChild(String name) { 649 return getNamedChild(name) != null; 650 } 651 652 public boolean hasChildren(String name) { 653 if (children != null) 654 for (Element child : children) 655 if (child.getName().equals(name)) 656 return true; 657 return false; 658 } 659 660 @Override 661 public String toString() { 662 return name + "=" + fhirType() + "[" 663 + (children == null || hasValue() ? value : Integer.toString(children.size()) + " children") + "]"; 664 } 665 666 @Override 667 public String getIdBase() { 668 return getChildValue("id"); 669 } 670 671 @Override 672 public void setIdBase(String value) { 673 setChildValue("id", value); 674 } 675 676 @Override 677 public boolean equalsDeep(Base other) { 678 if (!super.equalsDeep(other)) 679 return false; 680 if (isPrimitive() && other.isPrimitive()) 681 return primitiveValue().equals(other.primitiveValue()); 682 if (isPrimitive() || other.isPrimitive()) 683 return false; 684 Set<String> processed = new HashSet<String>(); 685 for (org.hl7.fhir.r4.model.Property p : children()) { 686 String name = p.getName(); 687 processed.add(name); 688 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 689 if (!equalsDeep(p, o)) 690 return false; 691 } 692 for (org.hl7.fhir.r4.model.Property p : children()) { 693 String name = p.getName(); 694 if (!processed.contains(name)) { 695 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 696 if (!equalsDeep(p, o)) 697 return false; 698 } 699 } 700 return true; 701 } 702 703 private boolean equalsDeep(org.hl7.fhir.r4.model.Property p, org.hl7.fhir.r4.model.Property o) { 704 if (o == null || p == null) 705 return false; 706 if (p.getValues().size() != o.getValues().size()) 707 return false; 708 for (int i = 0; i < p.getValues().size(); i++) 709 if (!Base.compareDeep(p.getValues().get(i), o.getValues().get(i), true)) 710 return false; 711 return true; 712 } 713 714 @Override 715 public boolean equalsShallow(Base other) { 716 if (!super.equalsShallow(other)) 717 return false; 718 if (isPrimitive() && other.isPrimitive()) 719 return primitiveValue().equals(other.primitiveValue()); 720 if (isPrimitive() || other.isPrimitive()) 721 return false; 722 return true; // ? 723 } 724 725 public Type asType() throws FHIRException { 726 return new ObjectConverter(property.getContext()).convertToType(this); 727 } 728 729 @Override 730 public boolean isMetadataBased() { 731 return true; 732 } 733 734 public boolean isList() { 735 if (elementProperty != null) 736 return elementProperty.isList(); 737 else 738 return property.isList(); 739 } 740 741 @Override 742 public String[] getTypesForProperty(int hash, String name) throws FHIRException { 743 Property p = property.getChildSimpleName(this.name, name); 744 if (p != null) { 745 Set<String> types = new HashSet<String>(); 746 for (TypeRefComponent tr : p.getDefinition().getType()) { 747 types.add(tr.getCode()); 748 } 749 return types.toArray(new String[] {}); 750 } 751 return super.getTypesForProperty(hash, name); 752 753 } 754 755 public void sort() { 756 if (children != null) { 757 List<Element> remove = new ArrayList<Element>(); 758 for (Element child : children) { 759 child.sort(); 760 if (child.isEmpty()) 761 remove.add(child); 762 } 763 children.removeAll(remove); 764 Collections.sort(children, new ElementSortComparator(this, this.property)); 765 } 766 } 767 768 public class ElementSortComparator implements Comparator<Element> { 769 private List<ElementDefinition> children; 770 771 public ElementSortComparator(Element e, Property property) { 772 String tn = e.getType(); 773 StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, 774 ProfileUtilities.sdNs(tn, property.getContext().getOverrideVersionNs())); 775 if (sd != null && !sd.getAbstract()) 776 children = sd.getSnapshot().getElement(); 777 else 778 children = property.getStructure().getSnapshot().getElement(); 779 } 780 781 @Override 782 public int compare(Element e0, Element e1) { 783 int i0 = find(e0); 784 int i1 = find(e1); 785 return Integer.compare(i0, i1); 786 } 787 788 private int find(Element e0) { 789 int i = e0.elementProperty != null ? children.indexOf(e0.elementProperty.getDefinition()) 790 : children.indexOf(e0.property.getDefinition()); 791 return i; 792 } 793 794 } 795 796 public class ICodingImpl implements ICoding { 797 private String system; 798 private String version; 799 private String code; 800 private String display; 801 private boolean doesSystem; 802 private boolean doesVersion; 803 private boolean doesCode; 804 private boolean doesDisplay; 805 806 public ICodingImpl(boolean doesCode, boolean doesSystem, boolean doesVersion, boolean doesDisplay) { 807 super(); 808 this.doesCode = doesCode; 809 this.doesSystem = doesSystem; 810 this.doesVersion = doesVersion; 811 this.doesDisplay = doesDisplay; 812 } 813 814 public String getSystem() { 815 return system; 816 } 817 818 public String getVersion() { 819 return version; 820 } 821 822 public String getCode() { 823 return code; 824 } 825 826 public String getDisplay() { 827 return display; 828 } 829 830 public boolean hasSystem() { 831 return !Utilities.noString(system); 832 } 833 834 public boolean hasVersion() { 835 return !Utilities.noString(version); 836 } 837 838 public boolean hasCode() { 839 return !Utilities.noString(code); 840 } 841 842 public boolean hasDisplay() { 843 return !Utilities.noString(display); 844 } 845 846 public boolean supportsSystem() { 847 return doesSystem; 848 } 849 850 public boolean supportsVersion() { 851 return doesVersion; 852 } 853 854 public boolean supportsCode() { 855 return doesCode; 856 } 857 858 public boolean supportsDisplay() { 859 return doesDisplay; 860 } 861 } 862 863 public ICoding getAsICoding() throws FHIRException { 864 if ("code".equals(fhirType())) { 865 if (property.getDefinition().getBinding().getStrength() != BindingStrength.REQUIRED) 866 return null; 867 ICodingImpl c = new ICodingImpl(true, true, false, false); 868 c.code = primitiveValue(); 869 ValueSetExpansionOutcome vse = property.getContext().expandVS(property.getDefinition().getBinding(), true, false); 870 if (vse.getValueset() == null) 871 return null; 872 for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { 873 if (cc.getCode().equals(c.code)) { 874 c.system = cc.getSystem(); 875 if (cc.hasVersion()) { 876 c.doesVersion = true; 877 c.version = cc.getVersion(); 878 } 879 if (cc.hasDisplay()) { 880 c.doesDisplay = true; 881 c.display = cc.getDisplay(); 882 } 883 } 884 } 885 if (c.system == null) 886 return null; 887 return c; 888 } else if ("Coding".equals(fhirType())) { 889 ICodingImpl c = new ICodingImpl(true, true, true, true); 890 c.system = getNamedChildValue("system"); 891 c.code = getNamedChildValue("code"); 892 c.display = getNamedChildValue("display"); 893 c.version = getNamedChildValue("version"); 894 return c; 895 } else if ("Quantity".equals(fhirType())) { 896 ICodingImpl c = new ICodingImpl(true, true, false, false); 897 c.system = getNamedChildValue("system"); 898 c.code = getNamedChildValue("code"); 899 return c; 900 } else 901 return null; 902 } 903 904 public String getExplicitType() { 905 return explicitType; 906 } 907 908 public void setExplicitType(String explicitType) { 909 this.explicitType = explicitType; 910 } 911 912}