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 setProperty(int hash, String name, Base value) throws FHIRException { 330 if ("xhtml".equals(getType()) && (hash == "value".hashCode())) { 331 this.xhtml = castToXhtml(value); 332 this.value = castToXhtmlString(value); 333 return this; 334 } 335 if (isPrimitive() && (hash == "value".hashCode())) { 336 this.value = castToString(value).asStringValue(); 337 return this; 338 } 339 340 if (!value.isPrimitive() && !(value instanceof Element)) { 341 if (isDataType(value)) 342 value = convertToElement(property.getChild(name), value); 343 else 344 throw new FHIRException("Cannot set property "+name+" on "+this.name+" - value is not a primitive type ("+value.fhirType()+") or an ElementModel type"); 345 } 346 347 if (children == null) 348 children = new ArrayList<Element>(); 349 Element childForValue = null; 350 351 // look through existing children 352 for (Element child : children) { 353 if (child.getName().equals(name)) { 354 if (!child.isList()) { 355 childForValue = child; 356 break; 357 } else { 358 Element ne = new Element(child); 359 children.add(ne); 360 numberChildren(); 361 childForValue = ne; 362 break; 363 } 364 } 365 } 366 367 int i = 0; 368 if (childForValue == null) 369 for (Property p : property.getChildProperties(this.name, type)) { 370 int t = -1; 371 for (int c =0; c < children.size(); c++) { 372 Element e = children.get(c); 373 if (p.getName().equals(e.getName())) 374 t = c; 375 } 376 if (t > i) 377 i = t; 378 if (p.getName().equals(name) || p.getName().equals(name+"[x]")) { 379 Element ne = new Element(name, p); 380 children.add(i, ne); 381 childForValue = ne; 382 break; 383 } 384 } 385 386 if (childForValue == null) 387 throw new Error("Cannot set property "+name+" on "+this.name); 388 else if (value.isPrimitive()) { 389 if (childForValue.property.getName().endsWith("[x]")) 390 childForValue.name = name+Utilities.capitalize(value.fhirType()); 391 childForValue.setValue(value.primitiveValue()); 392 } else { 393 Element ve = (Element) value; 394 childForValue.type = ve.getType(); 395 if (childForValue.property.getName().endsWith("[x]")) 396 childForValue.name = name+Utilities.capitalize(childForValue.type); 397 else if (value.isResource()) { 398 if (childForValue.elementProperty == null) 399 childForValue.elementProperty = childForValue.property; 400 childForValue.property = ve.property; 401 childForValue.special = SpecialElement.BUNDLE_ENTRY; 402 } 403 if (ve.children != null) { 404 if (childForValue.children == null) 405 childForValue.children = new ArrayList<Element>(); 406 else 407 childForValue.children.clear(); 408 childForValue.children.addAll(ve.children); 409 } 410 } 411 return childForValue; 412 } 413 414 private Base convertToElement(Property prop, Base v) throws FHIRException { 415 return new ObjectConverter(property.getContext()).convert(prop, (Type) v); 416 } 417 418 private boolean isDataType(Base v) { 419 return v instanceof Type && property.getContext().getTypeNames().contains(v.fhirType()); 420 } 421 422 @Override 423 public Base makeProperty(int hash, String name) throws FHIRException { 424 if (isPrimitive() && (hash == "value".hashCode())) { 425 return new StringType(value); 426 } 427 428 if (children == null) 429 children = new ArrayList<Element>(); 430 431 // look through existing children 432 for (Element child : children) { 433 if (child.getName().equals(name)) { 434 if (!child.isList()) { 435 return child; 436 } else { 437 Element ne = new Element(child); 438 children.add(ne); 439 numberChildren(); 440 return ne; 441 } 442 } 443 } 444 445 for (Property p : property.getChildProperties(this.name, type)) { 446 if (p.getName().equals(name)) { 447 Element ne = new Element(name, p); 448 children.add(ne); 449 return ne; 450 } 451 } 452 453 throw new Error("Unrecognised name "+name+" on "+this.name); 454 } 455 456 private int maxToInt(String max) { 457 if (max.equals("*")) 458 return Integer.MAX_VALUE; 459 else 460 return Integer.parseInt(max); 461 } 462 463 @Override 464 public boolean isPrimitive() { 465 return type != null ? property.isPrimitive(type) : property.isPrimitive(property.getType(name)); 466 } 467 468 @Override 469 public boolean isBooleanPrimitive() { 470 return isPrimitive() && ("boolean".equals(type) || "boolean".equals(property.getType(name))); 471 } 472 473 @Override 474 public boolean isResource() { 475 return property.isResource(); 476 } 477 478 479 @Override 480 public boolean hasPrimitiveValue() { 481 return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name); 482 } 483 484 485 @Override 486 public String primitiveValue() { 487 if (isPrimitive()) 488 return value; 489 else { 490 if (hasPrimitiveValue() && children != null) { 491 for (Element c : children) { 492 if (c.getName().equals("value")) 493 return c.primitiveValue(); 494 } 495 } 496 return null; 497 } 498 } 499 500 // for the validator 501 public int line() { 502 return line; 503 } 504 505 public int col() { 506 return col; 507 } 508 509 public Element markLocation(int line, int col) { 510 this.line = line; 511 this.col = col; 512 return this; 513 } 514 515 public void clearDecorations() { 516 clearUserData("fhir.decorations"); 517 for (Element e : children) 518 e.clearDecorations(); 519 } 520 521 public void markValidation(StructureDefinition profile, ElementDefinition definition) { 522 @SuppressWarnings("unchecked") 523 List<ElementDecoration> decorations = (List<ElementDecoration>) getUserData("fhir.decorations"); 524 if (decorations == null) { 525 decorations = new ArrayList<>(); 526 setUserData("fhir.decorations", decorations); 527 } 528 decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getUserString("path"), definition.getPath())); 529 if (definition.getId() != null && tail(definition.getId()).contains(":")) { 530 String[] details = tail(definition.getId()).split(":"); 531 decorations.add(new ElementDecoration(DecorationType.SLICE, null, details[1])); 532 } 533 } 534 535 private String tail(String id) { 536 return id.contains(".") ? id.substring(id.lastIndexOf(".")+1) : id; 537 } 538 539 public Element getNamedChild(String name) { 540 if (children == null) 541 return null; 542 Element result = null; 543 for (Element child : children) { 544 if (child.getName().equals(name)) { 545 if (result == null) 546 result = child; 547 else 548 throw new Error("Attempt to read a single element when there is more than one present ("+name+")"); 549 } 550 } 551 return result; 552 } 553 554 public void getNamedChildren(String name, List<Element> list) { 555 if (children != null) 556 for (Element child : children) 557 if (child.getName().equals(name)) 558 list.add(child); 559 } 560 561 public String getNamedChildValue(String name) { 562 Element child = getNamedChild(name); 563 return child == null ? null : child.value; 564 } 565 566 public void getNamedChildrenWithWildcard(String string, List<Element> values) { 567 Validate.isTrue(string.endsWith("[x]")); 568 569 String start = string.substring(0, string.length() - 3); 570 if (children != null) { 571 for (Element child : children) { 572 if (child.getName().startsWith(start)) { 573 values.add(child); 574 } 575 } 576 } 577 } 578 579 580 public XhtmlNode getXhtml() { 581 return xhtml; 582 } 583 584 public Element setXhtml(XhtmlNode xhtml) { 585 this.xhtml = xhtml; 586 return this; 587 } 588 589 @Override 590 public boolean isEmpty() { 591 // GG: this used to also test !"".equals(value). 592 // 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. 593 // it should not cause any problems in real life. 594 if (value != null) { 595 return false; 596 } 597 for (Element next : getChildren()) { 598 if (!next.isEmpty()) { 599 return false; 600 } 601 } 602 return true; 603 } 604 605 public Property getElementProperty() { 606 return elementProperty; 607 } 608 609 public boolean hasElementProperty() { 610 return elementProperty != null; 611 } 612 613 public boolean hasChild(String name) { 614 return getNamedChild(name) != null; 615 } 616 617 public boolean hasChildren(String name) { 618 if (children != null) 619 for (Element child : children) 620 if (child.getName().equals(name)) 621 return true; 622 return false; 623 } 624 625 @Override 626 public String toString() { 627 return name+"="+fhirType() + "["+(children == null || hasValue() ? value : Integer.toString(children.size())+" children")+"]"; 628 } 629 630 @Override 631 public String getIdBase() { 632 return getChildValue("id"); 633 } 634 635 @Override 636 public void setIdBase(String value) { 637 setChildValue("id", value); 638 } 639 640 641 @Override 642 public boolean equalsDeep(Base other) { 643 if (!super.equalsDeep(other)) 644 return false; 645 if (isPrimitive() && other.isPrimitive()) 646 return primitiveValue().equals(other.primitiveValue()); 647 if (isPrimitive() || other.isPrimitive()) 648 return false; 649 Set<String> processed = new HashSet<String>(); 650 for (org.hl7.fhir.r4.model.Property p : children()) { 651 String name = p.getName(); 652 processed.add(name); 653 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 654 if (!equalsDeep(p, o)) 655 return false; 656 } 657 for (org.hl7.fhir.r4.model.Property p : children()) { 658 String name = p.getName(); 659 if (!processed.contains(name)) { 660 org.hl7.fhir.r4.model.Property o = other.getChildByName(name); 661 if (!equalsDeep(p, o)) 662 return false; 663 } 664 } 665 return true; 666 } 667 668 private boolean equalsDeep(org.hl7.fhir.r4.model.Property p, org.hl7.fhir.r4.model.Property o) { 669 if (o == null || p == null) 670 return false; 671 if (p.getValues().size() != o.getValues().size()) 672 return false; 673 for (int i = 0; i < p.getValues().size(); i++) 674 if (!Base.compareDeep(p.getValues().get(i), o.getValues().get(i), true)) 675 return false; 676 return true; 677 } 678 679 @Override 680 public boolean equalsShallow(Base other) { 681 if (!super.equalsShallow(other)) 682 return false; 683 if (isPrimitive() && other.isPrimitive()) 684 return primitiveValue().equals(other.primitiveValue()); 685 if (isPrimitive() || other.isPrimitive()) 686 return false; 687 return true; //? 688 } 689 690 public Type asType() throws FHIRException { 691 return new ObjectConverter(property.getContext()).convertToType(this); 692 } 693 694 @Override 695 public boolean isMetadataBased() { 696 return true; 697 } 698 699 public boolean isList() { 700 if (elementProperty != null) 701 return elementProperty.isList(); 702 else 703 return property.isList(); 704 } 705 706 @Override 707 public String[] getTypesForProperty(int hash, String name) throws FHIRException { 708 Property p = property.getChildSimpleName(this.name, name); 709 if (p != null) { 710 Set<String> types = new HashSet<String>(); 711 for (TypeRefComponent tr : p.getDefinition().getType()) { 712 types.add(tr.getCode()); 713 } 714 return types.toArray(new String[]{}); 715 } 716 return super.getTypesForProperty(hash, name); 717 718 } 719 720 public void sort() { 721 if (children != null) { 722 List<Element> remove = new ArrayList<Element>(); 723 for (Element child : children) { 724 child.sort(); 725 if (child.isEmpty()) 726 remove.add(child); 727 } 728 children.removeAll(remove); 729 Collections.sort(children, new ElementSortComparator(this, this.property)); 730 } 731 } 732 733 public class ElementSortComparator implements Comparator<Element> { 734 private List<ElementDefinition> children; 735 public ElementSortComparator(Element e, Property property) { 736 String tn = e.getType(); 737 StructureDefinition sd = property.getContext().fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, property.getContext().getOverrideVersionNs())); 738 if (sd != null && !sd.getAbstract()) 739 children = sd.getSnapshot().getElement(); 740 else 741 children = property.getStructure().getSnapshot().getElement(); 742 } 743 744 @Override 745 public int compare(Element e0, Element e1) { 746 int i0 = find(e0); 747 int i1 = find(e1); 748 return Integer.compare(i0, i1); 749 } 750 private int find(Element e0) { 751 int i = e0.elementProperty != null ? children.indexOf(e0.elementProperty.getDefinition()) : children.indexOf(e0.property.getDefinition()); 752 return i; 753 } 754 755 } 756 757 public class ICodingImpl implements ICoding { 758 private String system; 759 private String version; 760 private String code; 761 private String display; 762 private boolean doesSystem; 763 private boolean doesVersion; 764 private boolean doesCode; 765 private boolean doesDisplay; 766 public ICodingImpl(boolean doesCode, boolean doesSystem, boolean doesVersion, boolean doesDisplay) { 767 super(); 768 this.doesCode = doesCode; 769 this.doesSystem = doesSystem; 770 this.doesVersion = doesVersion; 771 this.doesDisplay = doesDisplay; 772 } 773 public String getSystem() { 774 return system; 775 } 776 public String getVersion() { 777 return version; 778 } 779 public String getCode() { 780 return code; 781 } 782 public String getDisplay() { 783 return display; 784 } 785 public boolean hasSystem() { 786 return !Utilities.noString(system); 787 } 788 public boolean hasVersion() { 789 return !Utilities.noString(version); 790 } 791 public boolean hasCode() { 792 return !Utilities.noString(code); 793 } 794 public boolean hasDisplay() { 795 return !Utilities.noString(display); 796 } 797 public boolean supportsSystem() { 798 return doesSystem; 799 } 800 public boolean supportsVersion() { 801 return doesVersion; 802 } 803 public boolean supportsCode() { 804 return doesCode; 805 } 806 public boolean supportsDisplay() { 807 return doesDisplay; 808 } 809 } 810 811 public ICoding getAsICoding() throws FHIRException { 812 if ("code".equals(fhirType())) { 813 if (property.getDefinition().getBinding().getStrength() != BindingStrength.REQUIRED) 814 return null; 815 ICodingImpl c = new ICodingImpl(true, true, false, false); 816 c.code = primitiveValue(); 817 ValueSetExpansionOutcome vse = property.getContext().expandVS(property.getDefinition().getBinding(), true, false); 818 if (vse.getValueset() == null) 819 return null; 820 for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { 821 if (cc.getCode().equals(c.code)) { 822 c.system = cc.getSystem(); 823 if (cc.hasVersion()) { 824 c.doesVersion = true; 825 c.version = cc.getVersion(); 826 } 827 if (cc.hasDisplay()) { 828 c.doesDisplay = true; 829 c.display = cc.getDisplay(); 830 } 831 } 832 } 833 if (c.system == null) 834 return null; 835 return c; 836 } else if ("Coding".equals(fhirType())) { 837 ICodingImpl c = new ICodingImpl(true, true, true, true); 838 c.system = getNamedChildValue("system"); 839 c.code = getNamedChildValue("code"); 840 c.display = getNamedChildValue("display"); 841 c.version = getNamedChildValue("version"); 842 return c; 843 } else if ("Quantity".equals(fhirType())) { 844 ICodingImpl c = new ICodingImpl(true, true, false, false); 845 c.system = getNamedChildValue("system"); 846 c.code = getNamedChildValue("code"); 847 return c; 848 } else 849 return null; 850 } 851 852 public String getExplicitType() { 853 return explicitType; 854 } 855 856 public void setExplicitType(String explicitType) { 857 this.explicitType = explicitType; 858 } 859 860 861}