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 032 033import java.util.ArrayList; 034import java.util.Collections; 035import java.util.Comparator; 036import java.util.HashMap; 037import java.util.HashSet; 038import java.util.List; 039import java.util.Map; 040import java.util.Set; 041 042import org.apache.commons.lang3.Validate; 043import org.hl7.fhir.exceptions.FHIRException; 044import org.hl7.fhir.r4.conformance.ProfileUtilities; 045import org.hl7.fhir.r4.model.Base; 046import org.hl7.fhir.r4.model.ElementDefinition; 047import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; 048import org.hl7.fhir.r4.model.Enumerations.BindingStrength; 049import org.hl7.fhir.r4.model.ICoding; 050import org.hl7.fhir.r4.model.StringType; 051import org.hl7.fhir.r4.model.StructureDefinition; 052import org.hl7.fhir.r4.model.Type; 053import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent; 054import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 055import org.hl7.fhir.utilities.ElementDecoration; 056import org.hl7.fhir.utilities.ElementDecoration.DecorationType; 057import org.hl7.fhir.utilities.Utilities; 058import org.hl7.fhir.utilities.xhtml.XhtmlNode; 059 060/** 061 * This class represents the underlying reference model of FHIR 062 * 063 * A resource is nothing but a set of elements, where every element has a 064 * name, maybe a stated type, maybe an id, and either a value or child elements 065 * (one or the other, but not both or neither) 066 * 067 * @author Grahame Grieve 068 * 069 */ 070public class Element extends Base { 071 072 073 public enum SpecialElement { 074 CONTAINED, BUNDLE_ENTRY, BUNDLE_OUTCOME, PARAMETER; 075 076 public static SpecialElement fromProperty(Property property) { 077 if (property.getStructure().getIdElement().getIdPart().equals("Parameters")) 078 return PARAMETER; 079 if (property.getStructure().getIdElement().getIdPart().equals("Bundle") && property.getName().equals("resource")) 080 return BUNDLE_ENTRY; 081 if (property.getStructure().getIdElement().getIdPart().equals("Bundle") && property.getName().equals("outcome")) 082 return BUNDLE_OUTCOME; 083 if (property.getName().equals("contained")) 084 return CONTAINED; 085 throw new Error("Unknown resource containing a native resource: "+property.getDefinition().getId()); 086 } 087 } 088 089 private List<String> comments;// not relevant for production, but useful in documentation 090 private String name; 091 private String type; 092 private String value; 093 private int index = -1; 094 private List<Element> children; 095 private Property property; 096 private Property elementProperty; // this is used when special is set to true - it tracks the underlying element property which is used in a few places 097 private int line; 098 private int col; 099 private SpecialElement special; 100 private XhtmlNode xhtml; // if this is populated, then value will also hold the string representation 101 private String explicitType; // for xsi:type attribute 102 103 public Element(String name) { 104 super(); 105 this.name = name; 106 } 107 108 public Element(Element other) { 109 super(); 110 name = other.name; 111 type = other.type; 112 property = other.property; 113 elementProperty = other.elementProperty; 114 special = other.special; 115 } 116 117 public Element(String name, Property property) { 118 super(); 119 this.name = name; 120 this.property = property; 121 } 122 123 public Element(String name, Property property, String type, String value) { 124 super(); 125 this.name = name; 126 this.property = property; 127 this.type = type; 128 this.value = value; 129 } 130 131 public void updateProperty(Property property, SpecialElement special, Property elementProperty) { 132 this.property = property; 133 this.elementProperty = elementProperty; 134 this.special = special; 135 } 136 137 public SpecialElement getSpecial() { 138 return special; 139 } 140 141 public String getName() { 142 return name; 143 } 144 145 public String getType() { 146 if (type == null) 147 return property.getType(name); 148 else 149 return type; 150 } 151 152 public String getValue() { 153 return value; 154 } 155 156 public boolean hasChildren() { 157 return !(children == null || children.isEmpty()); 158 } 159 160 public List<Element> getChildren() { 161 if (children == null) 162 children = new ArrayList<Element>(); 163 return children; 164 } 165 166 public boolean hasComments() { 167 return !(comments == null || comments.isEmpty()); 168 } 169 170 public List<String> getComments() { 171 if (comments == null) 172 comments = new ArrayList<String>(); 173 return comments; 174 } 175 176 public Property getProperty() { 177 return property; 178 } 179 180 public void setValue(String value) { 181 this.value = value; 182 } 183 184 public void setType(String type) { 185 this.type = type; 186 187 } 188 189 public boolean hasValue() { 190 return value != null; 191 } 192 193 public List<Element> getChildrenByName(String name) { 194 List<Element> res = new ArrayList<Element>(); 195 if (hasChildren()) { 196 for (Element child : children) 197 if (name.equals(child.getName())) 198 res.add(child); 199 } 200 return res; 201 } 202 203 public void numberChildren() { 204 if (children == null) 205 return; 206 207 String last = ""; 208 int index = 0; 209 for (Element child : children) { 210 if (child.getProperty().isList()) { 211 if (last.equals(child.getName())) { 212 index++; 213 } else { 214 last = child.getName(); 215 index = 0; 216 } 217 child.index = index; 218 } else { 219 child.index = -1; 220 } 221 child.numberChildren(); 222 } 223 } 224 225 public int getIndex() { 226 return index; 227 } 228 229 public boolean hasIndex() { 230 return index > -1; 231 } 232 233 public void setIndex(int index) { 234 this.index = index; 235 } 236 237 public String getChildValue(String name) { 238 if (children == null) 239 return null; 240 for (Element child : children) { 241 if (name.equals(child.getName())) 242 return child.getValue(); 243 } 244 return null; 245 } 246 247 public void setChildValue(String name, String value) { 248 if (children == null) 249 children = new ArrayList<Element>(); 250 for (Element child : children) { 251 if (name.equals(child.getName())) { 252 if (!child.isPrimitive()) 253 throw new Error("Cannot set a value of a non-primitive type ("+name+" on "+this.getName()+")"); 254 child.setValue(value); 255 } 256 } 257 try { 258 setProperty(name.hashCode(), name, new StringType(value)); 259 } catch (FHIRException e) { 260 throw new Error(e); 261 } 262 } 263 264 public List<Element> getChildren(String name) { 265 List<Element> res = new ArrayList<Element>(); 266 if (children != null) 267 for (Element child : children) { 268 if (name.equals(child.getName())) 269 res.add(child); 270 } 271 return res; 272 } 273 274 public boolean hasType() { 275 if (type == null) 276 return property.hasType(name); 277 else 278 return true; 279 } 280 281 @Override 282 public String fhirType() { 283 return getType(); 284 } 285 286 @Override 287 public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException { 288 if (isPrimitive() && (hash == "value".hashCode()) && !Utilities.noString(value)) { 289// String tn = getType(); 290// throw new Error(tn+" not done yet"); 291 Base[] b = new Base[1]; 292 b[0] = new StringType(value); 293 return b; 294 } 295 296 List<Base> result = new ArrayList<Base>(); 297 if (children != null) { 298 for (Element child : children) { 299 if (child.getName().equals(name)) 300 result.add(child); 301 if (child.getName().startsWith(name) && child.getProperty().isChoice() && 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(), c.getProperty().getDefinition().getDefinition(), c.getProperty().getDefinition().getMin(), maxToInt(c.getProperty().getDefinition().getMax()), c); 319 childProps.add(p); 320 map.put(c.getName(), p); 321 322 } else 323 p.getValues().add(c); 324 } 325 } 326 } 327 328 @Override 329 public Base copy() { 330 Element element = new Element(this); 331 this.copyValues(element); 332 return element; 333 } 334 335 @Override 336 public void copyValues(Base dst) { 337 super.copyValues(dst); 338 339 Element dest = (Element) dst; 340 if (comments != null) { 341 dest.comments = new ArrayList<>(); 342 dest.comments.addAll(comments); 343 } else { 344 dest.comments = null; 345 } 346 dest.value = value; 347 if (children != null) { 348 dest.children = new ArrayList<>(); 349 for (Element child : children) { 350 dest.children.add((Element) child.copy()); 351 } 352 } else { 353 dest.children = null; 354 } 355 dest.line = line; 356 dest.col = col; 357 dest.xhtml = xhtml; 358 dest.explicitType = explicitType; 359 } 360 361 362 @Override 363 public Base setProperty(int hash, String name, Base value) throws FHIRException { 364 if ("xhtml".equals(getType()) && (hash == "value".hashCode())) { 365 this.xhtml = castToXhtml(value); 366 this.value = castToXhtmlString(value); 367 return this; 368 } 369 if (isPrimitive() && (hash == "value".hashCode())) { 370 this.value = castToString(value).asStringValue(); 371 return this; 372 } 373 374 if (!value.isPrimitive() && !(value instanceof Element)) { 375 if (isDataType(value)) 376 value = convertToElement(property.getChild(name), value); 377 else 378 throw new FHIRException("Cannot set property "+name+" on "+this.name+" - value is not a primitive type ("+value.fhirType()+") or an ElementModel type"); 379 } 380 381 if (children == null) 382 children = new ArrayList<Element>(); 383 Element childForValue = null; 384 385 // look through existing children 386 for (Element child : children) { 387 if (child.getName().equals(name)) { 388 if (!child.isList()) { 389 childForValue = child; 390 break; 391 } else { 392 Element ne = new Element(child); 393 children.add(ne); 394 numberChildren(); 395 childForValue = ne; 396 break; 397 } 398 } 399 } 400 401 int i = 0; 402 if (childForValue == null) 403 for (Property p : property.getChildProperties(this.name, type)) { 404 int t = -1; 405 for (int c =0; c < children.size(); c++) { 406 Element e = children.get(c); 407 if (p.getName().equals(e.getName())) 408 t = c; 409 } 410 if (t > i) 411 i = t; 412 if (p.getName().equals(name) || p.getName().equals(name+"[x]")) { 413 Element ne = new Element(name, p); 414 children.add(i, ne); 415 childForValue = ne; 416 break; 417 } 418 } 419 420 if (childForValue == null) 421 throw new Error("Cannot set property "+name+" on "+this.name); 422 else if (value.isPrimitive()) { 423 if (childForValue.property.getName().endsWith("[x]")) 424 childForValue.name = name+Utilities.capitalize(value.fhirType()); 425 childForValue.setValue(value.primitiveValue()); 426 } else { 427 Element ve = (Element) value; 428 childForValue.type = ve.getType(); 429 if (childForValue.property.getName().endsWith("[x]")) 430 childForValue.name = name+Utilities.capitalize(childForValue.type); 431 else if (value.isResource()) { 432 if (childForValue.elementProperty == null) 433 childForValue.elementProperty = childForValue.property; 434 childForValue.property = ve.property; 435 childForValue.special = SpecialElement.BUNDLE_ENTRY; 436 } 437 if (ve.children != null) { 438 if (childForValue.children == null) 439 childForValue.children = new ArrayList<Element>(); 440 else 441 childForValue.children.clear(); 442 childForValue.children.addAll(ve.children); 443 } 444 } 445 return childForValue; 446 } 447 448 private Base convertToElement(Property prop, Base v) throws FHIRException { 449 return new ObjectConverter(property.getContext()).convert(prop, (Type) v); 450 } 451 452 private boolean isDataType(Base v) { 453 return v instanceof Type && property.getContext().getTypeNames().contains(v.fhirType()); 454 } 455 456 @Override 457 public Base makeProperty(int hash, String name) throws FHIRException { 458 if (isPrimitive() && (hash == "value".hashCode())) { 459 return new StringType(value); 460 } 461 462 if (children == null) 463 children = new ArrayList<Element>(); 464 465 // look through existing children 466 for (Element child : children) { 467 if (child.getName().equals(name)) { 468 if (!child.isList()) { 469 return child; 470 } else { 471 Element ne = new Element(child); 472 children.add(ne); 473 numberChildren(); 474 return ne; 475 } 476 } 477 } 478 479 for (Property p : property.getChildProperties(this.name, type)) { 480 if (p.getName().equals(name)) { 481 Element ne = new Element(name, p); 482 children.add(ne); 483 return ne; 484 } 485 } 486 487 throw new Error("Unrecognised name "+name+" on "+this.name); 488 } 489 490 private int maxToInt(String max) { 491 if (max.equals("*")) 492 return Integer.MAX_VALUE; 493 else 494 return Integer.parseInt(max); 495 } 496 497 @Override 498 public boolean isPrimitive() { 499 return type != null ? property.isPrimitive(type) : property.isPrimitive(property.getType(name)); 500 } 501 502 @Override 503 public boolean isBooleanPrimitive() { 504 return isPrimitive() && ("boolean".equals(type) || "boolean".equals(property.getType(name))); 505 } 506 507 @Override 508 public boolean isResource() { 509 return property.isResource(); 510 } 511 512 513 @Override 514 public boolean hasPrimitiveValue() { 515 return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name); 516 } 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 614 public XhtmlNode getXhtml() { 615 return xhtml; 616 } 617 618 public Element setXhtml(XhtmlNode xhtml) { 619 this.xhtml = xhtml; 620 return this; 621 } 622 623 @Override 624 public boolean isEmpty() { 625 // GG: this used to also test !"".equals(value). 626 // the condition where "" is empty and there are no children is an error, and so this really only manifested as an issue in corner cases technical testing of the validator / FHIRPath. 627 // it should not cause any problems in real life. 628 if (value != null) { 629 return false; 630 } 631 for (Element next : getChildren()) { 632 if (!next.isEmpty()) { 633 return false; 634 } 635 } 636 return true; 637 } 638 639 public Property getElementProperty() { 640 return elementProperty; 641 } 642 643 public boolean hasElementProperty() { 644 return elementProperty != null; 645 } 646 647 public boolean hasChild(String name) { 648 return getNamedChild(name) != null; 649 } 650 651 public boolean hasChildren(String name) { 652 if (children != null) 653 for (Element child : children) 654 if (child.getName().equals(name)) 655 return true; 656 return false; 657 } 658 659 @Override 660 public String toString() { 661 return name+"="+fhirType() + "["+(children == null || hasValue() ? value : Integer.toString(children.size())+" children")+"]"; 662 } 663 664 @Override 665 public String getIdBase() { 666 return getChildValue("id"); 667 } 668 669 @Override 670 public void setIdBase(String value) { 671 setChildValue("id", value); 672 } 673 674 675 @Override 676 public boolean equalsDeep(Base other) { 677 if (!super.equalsDeep(other)) 678 return false; 679 if (isPrimitive() && other.isPrimitive()) 680 return primitiveValue().equals(other.primitiveValue()); 681 if (isPrimitive() || other.isPrimitive()) 682 return false; 683 Set<String> processed = new HashSet<String>(); 684 for (org.hl7.fhir.r4.model.Property p : children()) { 685 String name = p.getName(); 686 processed.add(name); 687 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 688 if (!equalsDeep(p, o)) 689 return false; 690 } 691 for (org.hl7.fhir.r4.model.Property p : children()) { 692 String name = p.getName(); 693 if (!processed.contains(name)) { 694 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 695 if (!equalsDeep(p, o)) 696 return false; 697 } 698 } 699 return true; 700 } 701 702 private boolean equalsDeep(org.hl7.fhir.r4.model.Property p, org.hl7.fhir.r4.model.Property o) { 703 if (o == null || p == null) 704 return false; 705 if (p.getValues().size() != o.getValues().size()) 706 return false; 707 for (int i = 0; i < p.getValues().size(); i++) 708 if (!Base.compareDeep(p.getValues().get(i), o.getValues().get(i), true)) 709 return false; 710 return true; 711 } 712 713 @Override 714 public boolean equalsShallow(Base other) { 715 if (!super.equalsShallow(other)) 716 return false; 717 if (isPrimitive() && other.isPrimitive()) 718 return primitiveValue().equals(other.primitiveValue()); 719 if (isPrimitive() || other.isPrimitive()) 720 return false; 721 return true; //? 722 } 723 724 public Type asType() throws FHIRException { 725 return new ObjectConverter(property.getContext()).convertToType(this); 726 } 727 728 @Override 729 public boolean isMetadataBased() { 730 return true; 731 } 732 733 public boolean isList() { 734 if (elementProperty != null) 735 return elementProperty.isList(); 736 else 737 return property.isList(); 738 } 739 740 @Override 741 public String[] getTypesForProperty(int hash, String name) throws FHIRException { 742 Property p = property.getChildSimpleName(this.name, name); 743 if (p != null) { 744 Set<String> types = new HashSet<String>(); 745 for (TypeRefComponent tr : p.getDefinition().getType()) { 746 types.add(tr.getCode()); 747 } 748 return types.toArray(new String[]{}); 749 } 750 return super.getTypesForProperty(hash, name); 751 752 } 753 754 public void sort() { 755 if (children != null) { 756 List<Element> remove = new ArrayList<Element>(); 757 for (Element child : children) { 758 child.sort(); 759 if (child.isEmpty()) 760 remove.add(child); 761 } 762 children.removeAll(remove); 763 Collections.sort(children, new ElementSortComparator(this, this.property)); 764 } 765 } 766 767 public class ElementSortComparator implements Comparator<Element> { 768 private List<ElementDefinition> children; 769 public ElementSortComparator(Element e, Property property) { 770 String tn = e.getType(); 771 StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, property.getContext().getOverrideVersionNs())); 772 if (sd != null && !sd.getAbstract()) 773 children = sd.getSnapshot().getElement(); 774 else 775 children = property.getStructure().getSnapshot().getElement(); 776 } 777 778 @Override 779 public int compare(Element e0, Element e1) { 780 int i0 = find(e0); 781 int i1 = find(e1); 782 return Integer.compare(i0, i1); 783 } 784 private int find(Element e0) { 785 int i = e0.elementProperty != null ? children.indexOf(e0.elementProperty.getDefinition()) : children.indexOf(e0.property.getDefinition()); 786 return i; 787 } 788 789 } 790 791 public class ICodingImpl implements ICoding { 792 private String system; 793 private String version; 794 private String code; 795 private String display; 796 private boolean doesSystem; 797 private boolean doesVersion; 798 private boolean doesCode; 799 private boolean doesDisplay; 800 public ICodingImpl(boolean doesCode, boolean doesSystem, boolean doesVersion, boolean doesDisplay) { 801 super(); 802 this.doesCode = doesCode; 803 this.doesSystem = doesSystem; 804 this.doesVersion = doesVersion; 805 this.doesDisplay = doesDisplay; 806 } 807 public String getSystem() { 808 return system; 809 } 810 public String getVersion() { 811 return version; 812 } 813 public String getCode() { 814 return code; 815 } 816 public String getDisplay() { 817 return display; 818 } 819 public boolean hasSystem() { 820 return !Utilities.noString(system); 821 } 822 public boolean hasVersion() { 823 return !Utilities.noString(version); 824 } 825 public boolean hasCode() { 826 return !Utilities.noString(code); 827 } 828 public boolean hasDisplay() { 829 return !Utilities.noString(display); 830 } 831 public boolean supportsSystem() { 832 return doesSystem; 833 } 834 public boolean supportsVersion() { 835 return doesVersion; 836 } 837 public boolean supportsCode() { 838 return doesCode; 839 } 840 public boolean supportsDisplay() { 841 return doesDisplay; 842 } 843 } 844 845 public ICoding getAsICoding() throws FHIRException { 846 if ("code".equals(fhirType())) { 847 if (property.getDefinition().getBinding().getStrength() != BindingStrength.REQUIRED) 848 return null; 849 ICodingImpl c = new ICodingImpl(true, true, false, false); 850 c.code = primitiveValue(); 851 ValueSetExpansionOutcome vse = property.getContext().expandVS(property.getDefinition().getBinding(), true, false); 852 if (vse.getValueset() == null) 853 return null; 854 for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { 855 if (cc.getCode().equals(c.code)) { 856 c.system = cc.getSystem(); 857 if (cc.hasVersion()) { 858 c.doesVersion = true; 859 c.version = cc.getVersion(); 860 } 861 if (cc.hasDisplay()) { 862 c.doesDisplay = true; 863 c.display = cc.getDisplay(); 864 } 865 } 866 } 867 if (c.system == null) 868 return null; 869 return c; 870 } else if ("Coding".equals(fhirType())) { 871 ICodingImpl c = new ICodingImpl(true, true, true, true); 872 c.system = getNamedChildValue("system"); 873 c.code = getNamedChildValue("code"); 874 c.display = getNamedChildValue("display"); 875 c.version = getNamedChildValue("version"); 876 return c; 877 } else if ("Quantity".equals(fhirType())) { 878 ICodingImpl c = new ICodingImpl(true, true, false, false); 879 c.system = getNamedChildValue("system"); 880 c.code = getNamedChildValue("code"); 881 return c; 882 } else 883 return null; 884 } 885 886 public String getExplicitType() { 887 return explicitType; 888 } 889 890 public void setExplicitType(String explicitType) { 891 this.explicitType = explicitType; 892 } 893 894 895}