From 6181d812e61600a53c5c427e4fe920192234d1a7 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 15 Nov 2023 14:20:54 +1100 Subject: [PATCH 1/3] Rework bundle references validation --- .../fhir/utilities/i18n/I18nConstants.java | 1 + .../src/main/resources/Messages.properties | 4 +- .../hl7/fhir/validation/BaseValidator.java | 154 ++++++++++-------- .../instance/InstanceValidator.java | 6 +- .../instance/type/BundleValidator.java | 102 ++++++++---- .../validation/instance/utils/NodeStack.java | 1 - .../validation/tests/ValidationTests.java | 2 +- 7 files changed, 160 insertions(+), 110 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index f829b2383..704824180 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -1026,6 +1026,7 @@ public class I18nConstants { public static final String BUNDLE_ENTRY_URL_MATCHES_TYPE_ID = "BUNDLE_ENTRY_URL_MATCHES_TYPE_ID"; public static final String BUNDLE_ENTRY_URL_MATCHES_NO_ID = "BUNDLE_ENTRY_URL_MATCHES_NO_ID"; public static final String BUNDLE_ENTRY_URL_ABSOLUTE = "BUNDLE_ENTRY_URL_ABSOLUTE"; + public static final String BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = "BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 2bf445919..6a84bccec 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -12,7 +12,9 @@ Bundle_BUNDLE_Entry_NoProfile_TYPE = No profile found for {0} resource of type ' Bundle_BUNDLE_Entry_NoProfile_EXPL = Specified profile {2} not found for {0} resource of type ''{0}'' Bundle_BUNDLE_Entry_NO_LOGICAL_EXPL = Specified logical model {1} not found for resource ''Binary/{0}'' Bundle_BUNDLE_Entry_NotFound = Can''t find ''{0}'' in the bundle ({1}) -BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT = Can''t find ''{0}'' in the bundle ({1}). Note that there is a resource in the bundle with the same type and id, but it does not match because of the fullUrl based rules around matching relative resources +BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = Found {0} matches for ''{1}'' in the bundle ({2}) +BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_one = Can''t find ''{1}'' in the bundle ({2}). Note that there is a resource in the bundle with the same type and id, but it does not match because of the fullUrl based rules around matching relative references (must be ``{3}``) +BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_other = Can''t find ''{1}'' in the bundle ({2}). Note that there are {0} resources in the bundle with the same type and id, but they do not match because of the fullUrl based rules around matching relative references (one of ``{3}``) Bundle_BUNDLE_Entry_Orphan_MESSAGE = Entry {0} isn''t reachable by traversing links (forward or backward) from the MessageHeader, so its presence should be reviewed (is it needed to process the message?) Bundle_BUNDLE_Entry_Orphan_DOCUMENT = Entry {0} isn''t reachable by traversing links (forward or backward) from the Composition BUNDLE_BUNDLE_ENTRY_REVERSE_R4 = Entry {0} isn''t reachable by traversing forwards from the Composition. Only Provenance is approved to be used this way (R4 section 3.3.1) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 7d69ede7c..d29fc0643 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -79,33 +79,12 @@ import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; -import org.hl7.fhir.validation.BaseValidator.ElementMatch; import org.hl7.fhir.validation.cli.utils.ValidationLevel; import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.NodeStack; public class BaseValidator implements IValidationContextResourceLoader { - - public class ElementMatch { - - private Element element; - private boolean valid; - protected ElementMatch(Element element, boolean valid) { - super(); - this.element = element; - this.valid = valid; - } - public Element getElement() { - return element; - } - public boolean isValid() { - return valid; - } - - } - - public class BooleanHolder { private boolean value = true; @@ -488,6 +467,10 @@ public class BaseValidator implements IValidationContextResourceLoader { return thePass; } + protected boolean rulePlural(List errors, String ruleDate, IssueType type, NodeStack node, boolean thePass, int num, String theMessage, Object... theMessageArguments) { + return rulePlural(errors, ruleDate, type, node.line(), node.col(), node.getLiteralPath(), thePass, num, theMessage, theMessageArguments); + } + protected boolean rulePlural(List errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) { if (!thePass && doingErrors()) { String message = context.formatMessagePlural(num, theMessage, theMessageArguments); @@ -771,6 +754,10 @@ public class BaseValidator implements IValidationContextResourceLoader { trackedMessages.removeAll(messages); } + protected boolean warningOrError(boolean isError, List errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String msg, Object... theMessageArguments) { + return warningOrError(isError, errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), thePass, msg, theMessageArguments); + } + protected boolean warningOrError(boolean isError, List errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { if (!thePass) { String nmsg = context.formatMessage(msg, theMessageArguments); @@ -1025,10 +1012,16 @@ public class BaseValidator implements IValidationContextResourceLoader { return null; } - protected ElementMatch resolveInBundle(Element bundle, List entries, String ref, String fullUrl, String type, String id) { + protected Element resolveInBundle(Element bundle, List entries, String ref, String fullUrl, String type, String id, NodeStack stack, List errors, String name, Element source, boolean isWarning) { + if ("MedicationStatement/d41ac499-c7e8-45fa-9246-69028bae178f".equals(ref)) { + System.out.println("!"); + } @SuppressWarnings("unchecked") - Map map = (Map) bundle.getUserData("validator.entrymap"); - Map relMap = (Map) bundle.getUserData("validator.entrymapR"); + Map> map = (Map>) bundle.getUserData("validator.entrymap"); + @SuppressWarnings("unchecked") + Map> relMap = (Map>) bundle.getUserData("validator.entrymapR"); + List list = null; + if (map == null) { map = new HashMap<>(); bundle.setUserData("validator.entrymap", map); @@ -1036,17 +1029,25 @@ public class BaseValidator implements IValidationContextResourceLoader { bundle.setUserData("validator.entrymapR", relMap); for (Element entry : entries) { String fu = entry.getNamedChildValue(FULL_URL); - map.put(fu, entry); + list = map.get(fu); + if (list == null) { + list = new ArrayList(); + map.put(fu, list); + } + list.add(entry); + Element resource = entry.getNamedChild(RESOURCE); if (resource != null) { String et = resource.getType(); String eid = resource.getNamedChildValue(ID); if (eid != null) { - if (VersionUtilities.isR4Plus(context.getVersion())) { - relMap.put(et+"/"+eid, entry); - } else { - map.put(et+"/"+eid, entry); + String rl = et+"/"+eid; + list = relMap.get(rl); + if (list == null) { + list = new ArrayList(); + relMap.put(rl, list); } + list.add(entry); } } } @@ -1054,58 +1055,73 @@ public class BaseValidator implements IValidationContextResourceLoader { if (Utilities.isAbsoluteUrl(ref)) { // if the reference is absolute, then you resolve by fullUrl. No other thinking is required. - Element e = map.get(ref); - if (e == null) { + List el = map.get(ref); + if (el == null) { + if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + warningOrError(!isWarning, errors, NO_RULE_DATE, IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); + } return null; + } else if (el.size() == 1) { + return el.get(0); } else { - return new ElementMatch(e, true); + if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); + } + return null; } -// for (Element entry : entries) { -// String fu = entry.getNamedChildValue(FULL_URL); -// if (ref.equals(fu)) -// return entry; -// } -// return null; } else { // split into base, type, and id String u = null; if (fullUrl != null && fullUrl.matches(urlRegex) && fullUrl.endsWith(type + "/" + id)) { - // fullUrl = complex u = fullUrl.substring(0, fullUrl.length() - (type + "/" + id).length()) + ref; } -// u = fullUrl.substring((type+"/"+id).length())+ref; - String[] parts = ref.split("\\/"); - if (parts.length >= 2) { - String t = parts[0]; - String i = parts[1]; - Element res = map.get(u); - if (res == null) { - res = map.get(t+"/"+i); - } - if (res == null && relMap.containsKey(t+"/"+i)) { - res = relMap.get(t+"/"+i); - return new ElementMatch(res, false); - } else if (res == null) { - return null; + List el = map.get(u); + if (el != null && el.size() > 0) { + if (el.size() == 1) { + return el.get(0); } else { - return new ElementMatch(res, true); + if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); + } + return null; } -// for (Element entry : entries) { -// String fu = entry.getNamedChildValue(FULL_URL); -// if (fu != null && fu.equals(u)) -// return entry; -// if (u == null) { -// Element resource = entry.getNamedChild(RESOURCE); -// if (resource != null) { -// String et = resource.getType(); -// String eid = resource.getNamedChildValue(ID); -// if (t.equals(et) && i.equals(eid)) -// return entry; -// } -// } -// } + } else { + String[] parts = ref.split("\\/"); + if (parts.length >= 2) { + String t = parts[0]; + if (context.getResourceNamesAsSet().contains(t)) { + String i = parts[1]; + el = relMap.get(t+"/"+i); + if (el != null) { + Set tl = new HashSet<>(); + for (Element e : el) { + String fu = e.getNamedChildValue(FULL_URL); + tl.add(fu == null ? "" : fu); + } + if (!VersionUtilities.isR4Plus(context.getVersion())) { + if (el.size() == 1) { + return el.get(0); + } else if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); + } + } else if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); + } + } else { + if (stack != null && !source.hasUserData("bundle.error.noted")) { + source.setUserData("bundle.error.noted", true); + warningOrError(!isWarning, errors, NO_RULE_DATE, IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); + } + } + } + } + return null; } - return null; } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 7cd442547..dde2151c2 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -5385,9 +5385,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!Utilities.noString(ref)) { for (Element bundle : bundles) { List entries = bundle.getChildren(ENTRY); - ElementMatch tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase()); - if (tgt != null && tgt.isValid()) { - element.setUserData("validator.bundle.resolution", tgt.getElement().getNamedChild(RESOURCE)); + Element tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase(), null, null, null, element, false); + if (tgt != null) { + element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE)); return; } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java index 48e9a0d75..f040223e0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java @@ -25,12 +25,40 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.validation.instance.PercentageTracker; +import org.hl7.fhir.validation.instance.type.BundleValidator.StringWithSource; import org.hl7.fhir.validation.instance.utils.EntrySummary; import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.ValidationContext; public class BundleValidator extends BaseValidator { + public class StringWithSource { + + private String reference; + private Element source; + private boolean warning; + + public StringWithSource(String reference, Element source, boolean warning) { + this.reference = reference; + this.source = source; + this.warning = warning; + } + + public String getReference() { + return reference; + } + + public Element getSource() { + return source; + } + + public boolean isWarning() { + return warning; + } + + } + + public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?"; private String serverBase; @@ -524,20 +552,18 @@ public class BundleValidator extends BaseValidator { public boolean validateDocumentReference(List errors, Element bundle, List entries, Element composition, NodeStack stack, String fullUrl, String id, boolean repeats, String propName, String title) { boolean ok = true; + + List list = new ArrayList<>(); + composition.getNamedChildren(propName, list); if (repeats) { - List list = new ArrayList<>(); - composition.getNamedChildren(propName, list); int i = 1; for (Element elem : list) { ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, i, null, null), fullUrl, "Composition", id) && ok; i++; } - - } else { - Element elem = composition.getNamedChild(propName); - if (elem != null) { - ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, -1, null, null), fullUrl, "Composition", id) && ok; - } + } else if (list.size() > 0) { + Element elem = list.get(0); + ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, -1, null, null), fullUrl, "Composition", id) && ok; } return ok; } @@ -561,11 +587,9 @@ public class BundleValidator extends BaseValidator { } if (ref != null && !Utilities.noString(reference) && !reference.startsWith("#")) { - ElementMatch target = resolveInBundle(bundle, entries, reference, fullUrl, type, id); + Element target = resolveInBundle(bundle, entries, reference, fullUrl, type, id, stack, errors, name, ref, false); if (target == null) { - return rule(errors, NO_RULE_DATE, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, reference, name); - } else { - return rule(errors, NO_RULE_DATE, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target.isValid(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, reference, name); + return false; } } return true; @@ -602,26 +626,23 @@ public class BundleValidator extends BaseValidator { if (r != null) { EntrySummary e = new EntrySummary(i, entry, r); entryList.add(e); -// System.out.println("Found entry "+e.dbg()); } i++; } for (EntrySummary e : entryList) { - Set references = findReferences(e.getEntry()); - for (String ref : references) { - ElementMatch tgt = resolveInBundle(bundle, entries, ref, e.getEntry().getChildValue(FULL_URL), e.getResource().fhirType(), e.getResource().getIdBase()); - if (tgt != null && tgt.isValid()) { - EntrySummary t = entryForTarget(entryList, tgt.getElement()); - if (t != null ) { - if (t != e) { -// System.out.println("Entry "+e.getIndex()+" refers to "+t.getIndex()+" by ref '"+ref+"'"); - e.getTargets().add(t); - } else { -// System.out.println("Entry "+e.getIndex()+" refers to itself by '"+ref+"'"); - } - } - } + List references = findReferences(e.getEntry()); + for (StringWithSource ref : references) { + Element tgt = resolveInBundle(bundle, entries, ref.getReference(), e.getEntry().getChildValue(FULL_URL), e.getResource().fhirType(), e.getResource().getIdBase(), stack, errors, ref.getSource().getPath(), ref.getSource(), ref.isWarning()); + if (tgt != null) { + EntrySummary t = entryForTarget(entryList, tgt); + if (t != null ) { + if (t != e) { + e.getTargets().add(t); + } else { + } + } + } } } @@ -801,29 +822,40 @@ public class BundleValidator extends BaseValidator { // } - private Set findReferences(Element start) { - Set references = new HashSet(); + private List findReferences(Element start) { + List references = new ArrayList(); findReferences(start, references); return references; } - private void findReferences(Element start, Set references) { + private void findReferences(Element start, List references) { for (Element child : start.getChildren()) { if (child.getType().equals("Reference")) { String ref = child.getChildValue("reference"); - if (ref != null && !ref.startsWith("#")) - references.add(ref); + if (ref != null && !ref.startsWith("#") && !hasReference(ref, references)) + references.add(new StringWithSource(ref, child, false)); } - if (child.getType().equals("url") || child.getType().equals("uri") || child.getType().equals("canonical")) { + if (Utilities.existsInList(child.getType(), "url", "uri"/*, "canonical"*/) && + !Utilities.existsInList(child.getName(), "system") && + !Utilities.existsInList(child.getProperty().getDefinition().getPath(), "Bundle.entry.fullUrl", "Coding.system", "Identifier.system", "Meta.profile", "Extension.url", "Quantity.system", + "MessageHeader.source.endpoint", "MessageHeader.destination.endpoint", "Endpoint.address")) { String ref = child.primitiveValue(); - if (ref != null && !ref.startsWith("#")) - references.add(ref); + if (ref != null && !ref.startsWith("#") && !hasReference(ref, references)) + references.add(new StringWithSource(ref, child, true)); } findReferences(child, references); } } + private boolean hasReference(String ref, List references) { + for (StringWithSource t : references) { + if (ref.equals(t.getReference())) { + return true; + } + } + return false; + } // hack for pre-UTG v2/v3 private boolean isV3orV2Url(String url) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/NodeStack.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/NodeStack.java index ee3cc6617..4f3a0ba4b 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/NodeStack.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/NodeStack.java @@ -245,5 +245,4 @@ public class NodeStack { return element.col(); } - } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index d4d2d83ad..c14e6d1d9 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -115,7 +115,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe private static final boolean BUILD_NEW = true; private static final boolean CLONE = true; - @Parameters(name = "{index}: id {0}") + @Parameters(name = "{0} (#{index})") public static Iterable data() throws IOException { String contents = TestingUtilities.loadTestResource("validator", "manifest.json"); From a7e8dc18a1bc7c4c9e049fe262a6c72c6498a21e Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 15 Nov 2023 17:34:13 +1100 Subject: [PATCH 2/3] #1488 - don't fail on erroneously repeating elements, and more bundle link validation --- .../org/hl7/fhir/r5/elementmodel/Element.java | 49 ++-- .../fhir/r5/renderers/ResourceRenderer.java | 2 +- .../hl7/fhir/validation/BaseValidator.java | 54 +++- .../hl7/fhir/validation/ValidationEngine.java | 2 +- .../instance/InstanceValidator.java | 252 +++++++++--------- .../instance/type/BundleValidator.java | 90 +++---- .../instance/type/CodeSystemValidator.java | 70 ++--- .../instance/type/ConceptMapValidator.java | 60 ++--- .../instance/type/MeasureValidator.java | 80 +++--- .../instance/type/ObservationValidator.java | 16 +- .../instance/type/QuestionnaireValidator.java | 56 ++-- .../type/SearchParameterValidator.java | 14 +- .../type/StructureDefinitionValidator.java | 136 +++++----- .../instance/type/StructureMapValidator.java | 22 +- .../instance/type/ValueSetValidator.java | 30 +-- .../instance/utils/EnableWhenEvaluator.java | 2 +- .../hl7/fhir/validation/ipa/IPAValidator.java | 6 +- 17 files changed, 492 insertions(+), 449 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java index 2c1128979..f742e3274 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java @@ -685,13 +685,16 @@ public class Element extends Base implements NamedItem { } public Element getNamedChild(String name) { + return getNamedChild(name, true); + } + public Element getNamedChild(String name, boolean exception) { if (children == null) return null; if (children.size() > 20) { List l = children.getByName(name); if (l == null || l.size() == 0) { // try the other way (in case of complicated naming rules) - } else if (l.size() > 1) { + } else if (l.size() > 1 && exception) { throw new Error("Attempt to read a single element when there is more than one present ("+name+")"); } else { return l.get(0); @@ -729,7 +732,11 @@ public class Element extends Base implements NamedItem { } public String getNamedChildValue(String name) { - Element child = getNamedChild(name); + return getNamedChildValue(name, true); + } + + public String getNamedChildValue(String name, boolean exception) { + Element child = getNamedChild(name, exception); return child == null ? null : child.value; } @@ -781,7 +788,11 @@ public class Element extends Base implements NamedItem { } public boolean hasChild(String name) { - return getNamedChild(name) != null; + return getNamedChild(name, true) != null; + } + + public boolean hasChild(String name, boolean exception) { + return getNamedChild(name, exception) != null; } public boolean hasChildren(String name) { @@ -1019,15 +1030,15 @@ public class Element extends Base implements NamedItem { return c; } else if ("Coding".equals(fhirType())) { ICodingImpl c = new ICodingImpl(true, true, true, true); - c.system = getNamedChildValue("system"); - c.code = getNamedChildValue("code"); - c.display = getNamedChildValue("display"); - c.version = getNamedChildValue("version"); + c.system = getNamedChildValue("system", false); + c.code = getNamedChildValue("code", false); + c.display = getNamedChildValue("display", false); + c.version = getNamedChildValue("version", false); return c; } else if ("Quantity".equals(fhirType())) { ICodingImpl c = new ICodingImpl(true, true, false, false); - c.system = getNamedChildValue("system"); - c.code = getNamedChildValue("code"); + c.system = getNamedChildValue("system", false); + c.code = getNamedChildValue("code", false); return c; } else return null; @@ -1072,7 +1083,7 @@ public class Element extends Base implements NamedItem { if (Utilities.existsInList(child.getName(), "extension", "modifierExtension")) { String u = child.getChildValue("url"); if (url.equals(u)) { - return child.getNamedChild("value"); + return child.getNamedChild("value", false); } } } @@ -1324,7 +1335,7 @@ public class Element extends Base implements NamedItem { for (Property p : property.getChildProperties(this.name, type)) { if (p.getName().equals(name)) { - if (!p.isList() && hasChild(name)) { + if (!p.isList() && hasChild(name, false)) { throw new Error(name+" on "+this.name+" is not a list, so can't add an element"); } Element ne = new Element(name, p).setFormat(format); @@ -1412,17 +1423,17 @@ public class Element extends Base implements NamedItem { public String getTranslation(String lang) { for (Element e : getChildren()) { if (e.fhirType().equals("Extension")) { - String url = e.getNamedChildValue("url"); + String url = e.getNamedChildValue("url", false); if (ToolingExtensions.EXT_TRANSLATION.equals(url)) { String l = null; String v = null; for (Element g : e.getChildren()) { if (g.fhirType().equals("Extension")) { - String u = g.getNamedChildValue("url"); + String u = g.getNamedChildValue("url", false); if ("lang".equals(u)) { - l = g.getNamedChildValue("value"); + l = g.getNamedChildValue("value", false); } else if ("value".equals(u)) { - v = g.getNamedChildValue("value"); + v = g.getNamedChildValue("value", false); } } } @@ -1451,17 +1462,17 @@ public class Element extends Base implements NamedItem { public void setTranslation(String lang, String translation) { for (Element e : getChildren()) { if (e.fhirType().equals("Extension")) { - String url = e.getNamedChildValue("url"); + String url = e.getNamedChildValue("url", false); if (ToolingExtensions.EXT_TRANSLATION.equals(url)) { String l = null; Element v = null; for (Element g : e.getChildren()) { if (g.fhirType().equals("Extension")) { - String u = g.getNamedChildValue("url"); + String u = g.getNamedChildValue("url", false); if ("lang".equals(u)) { - l = g.getNamedChildValue("value"); + l = g.getNamedChildValue("value", false); } else if ("value".equals(u)) { - v = g.getNamedChild("value"); + v = g.getNamedChild("value", false); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index 0c2d36960..406a51d28 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -358,7 +358,7 @@ public abstract class ResourceRenderer extends DataRenderer { org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version); if (bundleElement != null) { String bundleUrl = null; - Element br = bundleElement.getNamedChild("resource"); + Element br = bundleElement.getNamedChild("resource", false); if (br.getChildValue("id") != null) { bundleUrl = "#" + br.fhirType() + "_" + br.getChildValue("id"); } else { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index d29fc0643..6398659c6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -12,6 +12,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.naming.Context; + +import org.antlr.v4.codegen.model.decl.ContextTokenGetterDecl; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -770,6 +774,22 @@ public class BaseValidator implements IValidationContextResourceLoader { } + protected boolean hintOrError(boolean isError, List errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String msg, Object... theMessageArguments) { + return hintOrError(isError, errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), thePass, msg, theMessageArguments); + } + + protected boolean hintOrError(boolean isError, List errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { + if (!thePass) { + String nmsg = context.formatMessage(msg, theMessageArguments); + IssueSeverity lvl = isError ? IssueSeverity.ERROR : IssueSeverity.INFORMATION; + if (doingLevel(lvl)) { + addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, lvl, msg); + } + } + return thePass; + + } + /** * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * @@ -997,7 +1017,7 @@ public class BaseValidator implements IValidationContextResourceLoader { return null; if (bnd.fhirType().equals(BUNDLE)) { for (Element be : bnd.getChildrenByName(ENTRY)) { - Element res = be.getNamedChild(RESOURCE); + Element res = be.getNamedChild(RESOURCE, false); if (res != null) { String fullUrl = be.getChildValue(FULL_URL); String rt = res.fhirType(); @@ -1028,7 +1048,7 @@ public class BaseValidator implements IValidationContextResourceLoader { relMap = new HashMap<>(); bundle.setUserData("validator.entrymapR", relMap); for (Element entry : entries) { - String fu = entry.getNamedChildValue(FULL_URL); + String fu = entry.getNamedChildValue(FULL_URL, false); list = map.get(fu); if (list == null) { list = new ArrayList(); @@ -1036,10 +1056,10 @@ public class BaseValidator implements IValidationContextResourceLoader { } list.add(entry); - Element resource = entry.getNamedChild(RESOURCE); + Element resource = entry.getNamedChild(RESOURCE, false); if (resource != null) { String et = resource.getType(); - String eid = resource.getNamedChildValue(ID); + String eid = resource.getNamedChildValue(ID, false); if (eid != null) { String rl = et+"/"+eid; list = relMap.get(rl); @@ -1057,9 +1077,16 @@ public class BaseValidator implements IValidationContextResourceLoader { // if the reference is absolute, then you resolve by fullUrl. No other thinking is required. List el = map.get(ref); if (el == null) { - if (stack != null && !source.hasUserData("bundle.error.noted")) { + // if this something we complain about? + // not if it's in a package, or it looks like a restful URL and it's one of the canonical resource types + boolean ok = context.hasResource(Resource.class, ref); + if (!ok && ref.matches(urlRegex)) { + String tt = extractResourceType(ref); + ok = VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(tt); + } + if (!ok && stack != null && !source.hasUserData("bundle.error.noted")) { source.setUserData("bundle.error.noted", true); - warningOrError(!isWarning, errors, NO_RULE_DATE, IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); + hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } return null; } else if (el.size() == 1) { @@ -1098,7 +1125,7 @@ public class BaseValidator implements IValidationContextResourceLoader { if (el != null) { Set tl = new HashSet<>(); for (Element e : el) { - String fu = e.getNamedChildValue(FULL_URL); + String fu = e.getNamedChildValue(FULL_URL, false); tl.add(fu == null ? "" : fu); } if (!VersionUtilities.isR4Plus(context.getVersion())) { @@ -1115,7 +1142,7 @@ public class BaseValidator implements IValidationContextResourceLoader { } else { if (stack != null && !source.hasUserData("bundle.error.noted")) { source.setUserData("bundle.error.noted", true); - warningOrError(!isWarning, errors, NO_RULE_DATE, IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); + hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } } } @@ -1126,6 +1153,11 @@ public class BaseValidator implements IValidationContextResourceLoader { } + private String extractResourceType(String ref) { + String[] p = ref.split("\\/"); + return p[p.length -2]; + } + protected IndexedElement getFromBundle(Element bundle, String ref, String fullUrl, List errors, String path, String type, boolean isTransaction, BooleanHolder bh) { String targetUrl = null; String version = ""; @@ -1189,7 +1221,7 @@ public class BaseValidator implements IValidationContextResourceLoader { for (int i = 0; i < entries.size(); i++) { Element we = entries.get(i); if (targetUrl.equals(we.getChildValue(FULL_URL))) { - Element r = we.getNamedChild(RESOURCE); + Element r = we.getNamedChild(RESOURCE, false); if (version.isEmpty()) { rule(errors, NO_RULE_DATE, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref); match = r; @@ -1219,8 +1251,8 @@ public class BaseValidator implements IValidationContextResourceLoader { if (p.length >= 2 && context.getResourceNamesAsSet().contains(p[0]) && Utilities.isValidId(p[1])) { for (int i = 0; i < entries.size(); i++) { Element we = entries.get(i); - Element r = we.getNamedChild(RESOURCE); - if (r != null && p[0].equals(r.fhirType()) && p[1].equals(r.getNamedChildValue("id")) ) { + Element r = we.getNamedChild(RESOURCE, false); + if (r != null && p[0].equals(r.fhirType()) && p[1].equals(r.getNamedChildValue("id", false)) ) { ml.add(we); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index a1e9bc763..cd7cf08f9 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -968,7 +968,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus().getBytes()), cnt.getCntType()); // if the src has a url, we try to use the java code - if ((canDoNative == null && src.hasChild("url")) || (canDoNative != null && canDoNative)) { + if ((canDoNative == null && src.hasChild("url", false)) || (canDoNative != null && canDoNative)) { try { if (VersionUtilities.isR2Ver(version)) { return VersionConvertor.convertVersionNativeR2(targetVer, cnt, format); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index dde2151c2..a0faa5000 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -1054,12 +1054,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkAddress(List errors, String path, Element focus, Address fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".city", focus.getNamedChild("city"), fixed.getCityElement(), fixedSource, "city", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".state", focus.getNamedChild("state"), fixed.getStateElement(), fixedSource, "state", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".country", focus.getNamedChild("country"), fixed.getCountryElement(), fixedSource, "country", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".zip", focus.getNamedChild("zip"), fixed.getPostalCodeElement(), fixedSource, "postalCode", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".city", focus.getNamedChild("city", false), fixed.getCityElement(), fixedSource, "city", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".state", focus.getNamedChild("state", false), fixed.getStateElement(), fixedSource, "state", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".country", focus.getNamedChild("country", false), fixed.getCountryElement(), fixedSource, "country", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".zip", focus.getNamedChild("zip", false), fixed.getPostalCodeElement(), fixedSource, "postalCode", focus, pattern) && ok; List lines = new ArrayList(); focus.getNamedChildren("line", lines); @@ -1106,13 +1106,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkAttachment(List errors, String path, Element focus, Attachment fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".contentType", focus.getNamedChild("contentType"), fixed.getContentTypeElement(), fixedSource, "contentType", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".language", focus.getNamedChild("language"), fixed.getLanguageElement(), fixedSource, "language", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data"), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".url", focus.getNamedChild("url"), fixed.getUrlElement(), fixedSource, "url", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".size", focus.getNamedChild("size"), fixed.getSizeElement(), fixedSource, "size", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".hash", focus.getNamedChild("hash"), fixed.getHashElement(), fixedSource, "hash", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".title", focus.getNamedChild("title"), fixed.getTitleElement(), fixedSource, "title", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".contentType", focus.getNamedChild("contentType", false), fixed.getContentTypeElement(), fixedSource, "contentType", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".language", focus.getNamedChild("language", false), fixed.getLanguageElement(), fixedSource, "language", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data", false), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".url", focus.getNamedChild("url", false), fixed.getUrlElement(), fixedSource, "url", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".size", focus.getNamedChild("size", false), fixed.getSizeElement(), fixedSource, "size", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".hash", focus.getNamedChild("hash", false), fixed.getHashElement(), fixedSource, "hash", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".title", focus.getNamedChild("title", false), fixed.getTitleElement(), fixedSource, "title", focus, pattern) && ok; return ok; } @@ -1280,7 +1280,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCodeableConcept(List errors, String path, Element focus, CodeableConcept fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; List codings = new ArrayList(); focus.getNamedChildren("coding", codings); if (pattern) { @@ -1733,14 +1733,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean convertCDACodeToCodeableConcept(List errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) { boolean ok = true; - cc.setText(element.getNamedChildValue("originalText")); - if (element.hasChild("nullFlavor")) { - cc.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor", new CodeType(element.getNamedChildValue("nullFlavor"))); + cc.setText(element.getNamedChildValue("originalText", false)); + if (element.hasChild("nullFlavor", false)) { + cc.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor", new CodeType(element.getNamedChildValue("nullFlavor", false))); } - if (element.hasChild("code") || element.hasChild("codeSystem")) { + if (element.hasChild("code", false) || element.hasChild("codeSystem", false)) { Coding c = cc.addCoding(); - String oid = element.getNamedChildValue("codeSystem"); + String oid = element.getNamedChildValue("codeSystem", false); if (oid != null) { Set urls = context.urlsForOid(true, oid); if (urls.size() != 1) { @@ -1758,9 +1758,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); } - c.setCode(element.getNamedChildValue("code")); - c.setVersion(element.getNamedChildValue("codeSystemVersion")); - c.setDisplay(element.getNamedChildValue("displayName")); + c.setCode(element.getNamedChildValue("code", false)); + c.setVersion(element.getNamedChildValue("codeSystemVersion", false)); + c.setDisplay(element.getNamedChildValue("displayName", false)); } // todo: translations return ok; @@ -1920,22 +1920,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCoding(List errors, String path, Element focus, Coding fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".version", focus.getNamedChild("version"), fixed.getVersionElement(), fixedSource, "version", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code"), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display"), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".userSelected", focus.getNamedChild("userSelected"), fixed.getUserSelectedElement(), fixedSource, "userSelected", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".version", focus.getNamedChild("version", false), fixed.getVersionElement(), fixedSource, "version", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code", false), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display", false), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".userSelected", focus.getNamedChild("userSelected", false), fixed.getUserSelectedElement(), fixedSource, "userSelected", focus, pattern) && ok; return ok; } private boolean checkCoding(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack) { - String code = element.getNamedChildValue("code"); - String system = element.getNamedChildValue("system"); + String code = element.getNamedChildValue("code", false); + String system = element.getNamedChildValue("system", false); if (code != null && system == null) { warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); } - String version = element.getNamedChildValue("version"); - String display = element.getNamedChildValue("display"); + String version = element.getNamedChildValue("version", false); + String display = element.getNamedChildValue("display", false); return checkCodedElement(errors, path, element, profile, theElementCntext, inCodeableConcept, checkDisplay, stack, code, system, version, display); } @@ -2051,16 +2051,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkContactPoint(List errors, String path, Element focus, ContactPoint fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; return ok; } private boolean checkExtension(ValidationContext valContext, List errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { boolean ok = true; - String url = element.getNamedChildValue("url"); + String url = element.getNamedChildValue("url", false); String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url; boolean isModifier = element.getName().equals("modifierExtension"); assert def.getIsModifier() == isModifier; @@ -2262,10 +2262,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (stack.getElement().getName().startsWith("value")) { NodeStack estack = stack.getParent(); if (estack != null && estack.getElement().fhirType().equals("Extension")) { - ext = estack.getElement().getNamedChildValue("url"); + ext = estack.getElement().getNamedChildValue("url", false); } } else { - ext = stack.getElement().getNamedChildValue("url"); + ext = stack.getElement().getNamedChildValue("url", false); } if (ctxt.getExpression().equals(ext)) { ok = true; @@ -2496,7 +2496,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat for (Extension e : fixed.getExtension()) { Element ex = getExtensionByUrl(extensions, e.getUrl()); if (rule(errors, NO_RULE_DATE, IssueType.VALUE, focus.line(), focus.col(), path, ex != null, I18nConstants.EXTENSION_EXT_COUNT_NOTFOUND, e.getUrl())) { - ok = checkFixedValue(errors, path, ex.getNamedChild("extension").getNamedChild("value"), e.getValue(), fixedSource, "extension.value", ex.getNamedChild("extension"), false) && ok; + ok = checkFixedValue(errors, path, ex.getNamedChild("extension", false).getNamedChild("value", false), e.getValue(), fixedSource, "extension.value", ex.getNamedChild("extension", false), false) && ok; } else { ok = false; } @@ -2510,9 +2510,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkHumanName(List errors, String path, Element focus, HumanName fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern); - ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern); - ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern); + ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern); + ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern); + ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern); List parts = new ArrayList(); if (!pattern || fixed.hasFamily()) { @@ -2556,10 +2556,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkIdentifier(List errors, String path, Element element, ElementDefinition context) { boolean ok = true; - String system = element.getNamedChildValue("system"); + String system = element.getNamedChildValue("system", false); ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, system == null || isIdentifierSystemReferenceValid(system), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_SYSTEM) && ok; if ("urn:ietf:rfc:3986".equals(system)) { - String value = element.getNamedChildValue("value"); + String value = element.getNamedChildValue("value", false); ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, value == null || isAbsolute(value), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_IETF_SYSTEM_VALUE, value) && ok; } return ok; @@ -2567,19 +2567,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkIdentifier(List errors, String path, Element focus, Identifier fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".type", focus.getNamedChild(TYPE), fixed.getType(), fixedSource, TYPE, focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".assigner", focus.getNamedChild("assigner"), fixed.getAssigner(), fixedSource, "assigner", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".type", focus.getNamedChild(TYPE, false), fixed.getType(), fixedSource, TYPE, focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".assigner", focus.getNamedChild("assigner", false), fixed.getAssigner(), fixedSource, "assigner", focus, pattern) && ok; return ok; } private boolean checkPeriod(List errors, String path, Element focus, Period fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".start", focus.getNamedChild("start"), fixed.getStartElement(), fixedSource, "start", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), fixedSource, "end", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".start", focus.getNamedChild("start", false), fixed.getStartElement(), fixedSource, "start", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".end", focus.getNamedChild("end", false), fixed.getEndElement(), fixedSource, "end", focus, pattern) && ok; return ok; } @@ -3409,20 +3409,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkQuantity(List errors, String path, Element focus, Quantity fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator"), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".unit", focus.getNamedChild("unit"), fixed.getUnitElement(), fixedSource, "unit", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code"), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator", false), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".unit", focus.getNamedChild("unit", false), fixed.getUnitElement(), fixedSource, "unit", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code", false), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; return ok; } private boolean checkQuantity(List errors, String path, Element element, StructureDefinition theProfile, ElementDefinition definition, NodeStack theStack) { boolean ok = true; - String value = element.hasChild("value") ? element.getNamedChild("value").getValue() : null; - String unit = element.hasChild("unit") ? element.getNamedChild("unit").getValue() : null; - String system = element.hasChild("system") ? element.getNamedChild("system").getValue() : null; - String code = element.hasChild("code") ? element.getNamedChild("code").getValue() : null; + String value = element.hasChild("value", false) ? element.getNamedChild("value", false).getValue() : null; + String unit = element.hasChild("unit", false) ? element.getNamedChild("unit", false).getValue() : null; + String system = element.hasChild("system", false) ? element.getNamedChild("system", false).getValue() : null; + String code = element.hasChild("code", false) ? element.getNamedChild("code", false).getValue() : null; // todo: allowedUnits http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits - codeableConcept, or canonical(ValueSet) // todo: http://hl7.org/fhir/StructureDefinition/iso21090-PQ-translation @@ -3575,17 +3575,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat long size = -1; // first check size String fetchError = null; - if (element.hasChild("data")) { + if (element.hasChild("data", false)) { String b64 = element.getChildValue("data"); // Note: If the value isn't valid, we're not adding an error here, as the test to the // child Base64Binary will catch it and we don't want to log it twice boolean bok = isValidBase64(b64); - if (bok && element.hasChild("size")) { + if (bok && element.hasChild("size", false)) { size = countBase64DecodedBytes(b64); String sz = element.getChildValue("size"); ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Long.toString(size).equals(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_CORRECT, sz, size) && ok; } - } else if (element.hasChild("size")) { + } else if (element.hasChild("size", false)) { String sz = element.getChildValue("size"); if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Utilities.isLong(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID, sz)) { size = Long.parseLong(sz); @@ -3593,7 +3593,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { ok = false; } - } else if (element.hasChild("url")) { + } else if (element.hasChild("url", false)) { String url = element.getChildValue("url"); if (definition.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) { try { @@ -3620,7 +3620,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_TOO_LONG, size, def) && ok; } } - warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, (element.hasChild("data") || element.hasChild("url")) || (element.hasChild("contentType") || element.hasChild("language")), + warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, (element.hasChild("data", false) || element.hasChild("url", false)) || (element.hasChild("contentType", false) || element.hasChild("language", false)), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_NO_CONTENT); return ok; } @@ -3629,15 +3629,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkRange(List errors, String path, Element focus, Range fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".low", focus.getNamedChild("low"), fixed.getLow(), fixedSource, "low", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".high", focus.getNamedChild("high"), fixed.getHigh(), fixedSource, "high", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".low", focus.getNamedChild("low", false), fixed.getLow(), fixedSource, "low", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".high", focus.getNamedChild("high", false), fixed.getHigh(), fixedSource, "high", focus, pattern) && ok; return ok; } private boolean checkRatio(List errors, String path, Element focus, Ratio fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".numerator", focus.getNamedChild("numerator"), fixed.getNumerator(), fixedSource, "numerator", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".denominator", focus.getNamedChild("denominator"), fixed.getDenominator(), fixedSource, "denominator", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".numerator", focus.getNamedChild("numerator", false), fixed.getNumerator(), fixedSource, "numerator", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".denominator", focus.getNamedChild("denominator", false), fixed.getDenominator(), fixedSource, "denominator", focus, pattern) && ok; return ok; } @@ -3657,7 +3657,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!path.contains("element.pattern")) { // this business rule doesn't apply to patterns if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) { warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, - !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY); + !Utilities.noString(element.getNamedChildValue("display", false)), I18nConstants.REFERENCE_REF_NODISPLAY); } } return true; @@ -4034,33 +4034,33 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkSampledData(List errors, String path, Element focus, SampledData fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".origin", focus.getNamedChild("origin"), fixed.getOrigin(), fixedSource, "origin", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".origin", focus.getNamedChild("origin", false), fixed.getOrigin(), fixedSource, "origin", focus, pattern) && ok; if (VersionUtilities.isR5VerOrLater(context.getVersion())) { - ok = checkFixedValue(errors, path + ".interval", focus.getNamedChild("period"), fixed.getIntervalElement(), fixedSource, "interval", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".intervalUnit", focus.getNamedChild("period"), fixed.getIntervalUnitElement(), fixedSource, "intervalUnit", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".interval", focus.getNamedChild("period", false), fixed.getIntervalElement(), fixedSource, "interval", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".intervalUnit", focus.getNamedChild("period", false), fixed.getIntervalUnitElement(), fixedSource, "intervalUnit", focus, pattern) && ok; } else { - ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getIntervalElement(), fixedSource, "period", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getIntervalElement(), fixedSource, "period", focus, pattern) && ok; } - ok = checkFixedValue(errors, path + ".factor", focus.getNamedChild("factor"), fixed.getFactorElement(), fixedSource, "factor", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".lowerLimit", focus.getNamedChild("lowerLimit"), fixed.getLowerLimitElement(), fixedSource, "lowerLimit", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".upperLimit", focus.getNamedChild("upperLimit"), fixed.getUpperLimitElement(), fixedSource, "upperLimit", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".dimensions", focus.getNamedChild("dimensions"), fixed.getDimensionsElement(), fixedSource, "dimensions", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data"), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".factor", focus.getNamedChild("factor", false), fixed.getFactorElement(), fixedSource, "factor", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".lowerLimit", focus.getNamedChild("lowerLimit", false), fixed.getLowerLimitElement(), fixedSource, "lowerLimit", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".upperLimit", focus.getNamedChild("upperLimit", false), fixed.getUpperLimitElement(), fixedSource, "upperLimit", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".dimensions", focus.getNamedChild("dimensions", false), fixed.getDimensionsElement(), fixedSource, "dimensions", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data", false), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; return ok; } private boolean checkReference(List errors, String path, Element focus, Reference fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".reference", focus.getNamedChild("reference"), fixed.getReferenceElement_(), fixedSource, "reference", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".type", focus.getNamedChild("type"), fixed.getTypeElement(), fixedSource, "type", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".identifier", focus.getNamedChild("identifier"), fixed.getIdentifier(), fixedSource, "identifier", focus, pattern) && ok; - ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display"), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".reference", focus.getNamedChild("reference", false), fixed.getReferenceElement_(), fixedSource, "reference", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".type", focus.getNamedChild("type", false), fixed.getTypeElement(), fixedSource, "type", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".identifier", focus.getNamedChild("identifier", false), fixed.getIdentifier(), fixedSource, "identifier", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display", false), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; return ok; } private boolean checkTiming(List errors, String path, Element focus, Timing fixed, String fixedSource, boolean pattern) { boolean ok = true; - ok = checkFixedValue(errors, path + ".repeat", focus.getNamedChild("repeat"), fixed.getRepeat(), fixedSource, "value", focus, pattern) && ok; + ok = checkFixedValue(errors, path + ".repeat", focus.getNamedChild("repeat", false), fixed.getRepeat(), fixedSource, "value", focus, pattern) && ok; List events = new ArrayList(); focus.getNamedChildren("event", events); @@ -4157,7 +4157,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat container.getNamedChildren("contained", contained); for (int i = 0; i < contained.size(); i++) { Element we = contained.get(i); - if (id.equals(we.getNamedChildValue(ID))) { + if (id.equals(we.getNamedChildValue(ID, false))) { return new IndexedElement(i, we, null); } } @@ -4235,7 +4235,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private Element getExtensionByUrl(List extensions, String urlSimple) { for (Element e : extensions) { - if (urlSimple.equals(e.getNamedChildValue("url"))) + if (urlSimple.equals(e.getNamedChildValue("url", false))) return e; } return null; @@ -4556,8 +4556,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat int i = 0; for (Element child : params.getElement().getChildren("parameter")) { NodeStack p = params.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition()); - if (child.hasChild("resource")) { - Element res = child.getNamedChild("resource"); + if (child.hasChild("resource", false)) { + Element res = child.getNamedChild("resource", false); if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) { return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition()); } @@ -4574,8 +4574,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat int i = 0; for (Element child : param.getChildren("part")) { NodeStack p = pp.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition()); - if (child.hasChild("resource")) { - Element res = child.getNamedChild("resource"); + if (child.hasChild("resource", false)) { + Element res = child.getNamedChild("resource", false); if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) { return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition()); } @@ -5216,7 +5216,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } - Element meta = element.getNamedChild(META); + Element meta = element.getNamedChild(META, false); if (meta != null) { List profiles = new ArrayList(); meta.getNamedChildren("profile", profiles); @@ -5361,7 +5361,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat List entries = element.getChildrenByName(ENTRY); for (Element entry : entries) { String fu = entry.getChildValue(FULL_URL); - Element r = entry.getNamedChild(RESOURCE); + Element r = entry.getNamedChild(RESOURCE, false); if (r != null) { resolveBundleReferencesInResource(list, r, fu); } @@ -5387,7 +5387,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat List entries = bundle.getChildren(ENTRY); Element tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase(), null, null, null, element, false); if (tgt != null) { - element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE)); + element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE, false)); return; } } @@ -5443,7 +5443,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) { Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS); String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null; - String status = element.getNamedChildValue("status"); + String status = element.getNamedChildValue("status", false); if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) { if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) { hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); @@ -5499,14 +5499,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkPublisherConsistency(List errors, Element element, NodeStack stack) { - String pub = element.getNamedChildValue("publisher"); + String pub = element.getNamedChildValue("publisher", false); Base wgT = element.getExtensionValue(ToolingExtensions.EXT_WORKGROUP); String wg = wgT == null ? null : wgT.primitiveValue(); List urls = new ArrayList<>(); for (Element c : element.getChildren("contact")) { for (Element t : c.getChildren("telecom")) { - if ("url".equals(t.getNamedChildValue("system")) && t.getNamedChildValue("value") != null) { - urls.add(t.getNamedChildValue("value")); + if ("url".equals(t.getNamedChildValue("system", false)) && t.getNamedChildValue("value", false) != null) { + urls.add(t.getNamedChildValue("value", false)); } } } @@ -5561,17 +5561,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } private void checkLang(Element resource, NodeStack stack) { - String lang = resource.getNamedChildValue("language"); + String lang = resource.getNamedChildValue("language", false); if (!Utilities.noString(lang)) stack.setWorkingLang(lang); } private boolean validateResourceRules(List errors, Element element, NodeStack stack) { boolean ok= true; - String lang = element.getNamedChildValue("language"); - Element text = element.getNamedChild("text"); + String lang = element.getNamedChildValue("language", false); + Element text = element.getNamedChild("text", false); if (text != null) { - Element div = text.getNamedChild("div"); + Element div = text.getNamedChild("div", false); if (lang != null && div != null) { XhtmlNode xhtml = div.getXhtml(); String l = xhtml.getAttribute("lang"); @@ -5593,14 +5593,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } // security tags are a set (system|code) - Element meta = element.getNamedChild(META); + Element meta = element.getNamedChild(META, false); if (meta != null) { Set tags = new HashSet<>(); List list = new ArrayList<>(); meta.getNamedChildren("security", list); int i = 0; for (Element e : list) { - String s = e.getNamedChildValue("system") + "#" + e.getNamedChildValue("code"); + String s = e.getNamedChildValue("system", false) + "#" + e.getNamedChildValue("code", false); ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, e.line(), e.col(), stack.getLiteralPath() + ".meta.profile[" + Integer.toString(i) + "]", !tags.contains(s), I18nConstants.META_RES_SECURITY_DUPLICATE, s) && ok; tags.add(s); i++; @@ -5903,10 +5903,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_PROFILE_STYLE) && "cda".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE))) { List templates = element.getChildren("templateId"); for (Element t : templates) { - String tid = t.hasChild("extension") ? "urn:hl7ii:"+t.getChildValue("root")+ ":"+t.getChildValue("extension") : "urn:oid:"+t.getChildValue("root"); + String tid = t.hasChild("extension", false) ? "urn:hl7ii:"+t.getChildValue("root")+ ":"+t.getChildValue("extension") : "urn:oid:"+t.getChildValue("root"); StructureDefinition sd = cu.fetchProfileByIdentifier(tid); if (sd == null) { - hint(errors, "2023-10-20", IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, t.hasChild("extension") ? I18nConstants.CDA_UNKNOWN_TEMPLATE_EXT : I18nConstants.CDA_UNKNOWN_TEMPLATE, t.getChildValue("root"), t.getChildValue("extension")); + hint(errors, "2023-10-20", IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, t.hasChild("extension", false) ? I18nConstants.CDA_UNKNOWN_TEMPLATE_EXT : I18nConstants.CDA_UNKNOWN_TEMPLATE, t.getChildValue("root"), t.getChildValue("extension")); } else { ElementDefinition ed = sd.getSnapshot().getElementFirstRep(); if (!element.hasValidated(sd, ed)) { @@ -6152,7 +6152,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ok = checkReference(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack, pct, mode) && ok; // We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension } else if (type.equals("Extension")) { - Element eurl = ei.getElement().getNamedChild("url"); + Element eurl = ei.getElement().getNamedChild("url", false); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.getPath(), eurl != null, I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) { String url = eurl.primitiveValue(); thisExtension = url; @@ -6178,7 +6178,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (defn != null && defn.hasExtension(ToolingExtensions.EXT_BINDING_STYLE)) { String style = ToolingExtensions.readStringExtension(defn, ToolingExtensions.EXT_BINDING_STYLE); if ("CDA".equals(style)) { - if (!ei.getElement().hasChild("nullFlavor")) { + if (!ei.getElement().hasChild("nullFlavor", false)) { if (cdaTypeIs(defn, "CS")) { ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok; } else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) { @@ -6299,8 +6299,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCDACoding(List errors, String path, boolean isPQ, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn, boolean inCodeableConcept, boolean checkDisplay) { boolean ok = true; String system = null; - String code = element.getNamedChildValue(isPQ ? "unit" : "code"); - String oid = isPQ ? "2.16.840.1.113883.6.8" : element.getNamedChildValue("codeSystem"); + String code = element.getNamedChildValue(isPQ ? "unit" : "code", false); + String oid = isPQ ? "2.16.840.1.113883.6.8" : element.getNamedChildValue("codeSystem", false); if (oid != null) { Set urls = context.urlsForOid(true, oid); if (urls.size() != 1) { @@ -6319,14 +6319,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, code == null, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); } - String version = element.getNamedChildValue("codeSystemVersion"); - String display = element.getNamedChildValue("displayName"); + String version = element.getNamedChildValue("codeSystemVersion", false); + String display = element.getNamedChildValue("displayName", false); return checkCodedElement(errors, path, element, profile, checkDefn, inCodeableConcept, checkDisplay, stack, code, system, version, display) && ok; } private boolean checkCDACodeSimple(ValidationContext valContext, List errors, String path, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn) { - if (element.hasChild("code")) { - return checkPrimitiveBinding(valContext, errors, path, "code", checkDefn, element.getNamedChild("code"), profile, stack); + if (element.hasChild("code", false)) { + return checkPrimitiveBinding(valContext, errors, path, "code", checkDefn, element.getNamedChild("code", false), profile, stack); } else { return false; } @@ -6487,7 +6487,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (ed.hasSlicing()) { if (slicer != null && slicer.getPath().equals(ed.getPath())) { String errorContext = "profile " + profile.getVersionedUrl(); - if (resource.hasChild(ID) && !resource.getChildValue(ID).isEmpty()) { + if (resource.hasChild(ID, false) && !resource.getChildValue(ID).isEmpty()) { errorContext += "; instance " + resource.getChildValue("id"); } throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext)); @@ -6670,14 +6670,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (ei.getDefinition().hasExtension(ToolingExtensions.EXT_ID_EXPECTATION)) { return IdStatus.fromCode(ToolingExtensions.readStringExtension(ei.getDefinition(),ToolingExtensions.EXT_ID_EXPECTATION)); } else if (isBundleEntry(ei.getPath())) { - Element req = ep.getNamedChild("request"); - Element resp = ep.getNamedChild("response"); - Element fullUrl = ep.getNamedChild(FULL_URL); + Element req = ep.getNamedChild("request", false); + Element resp = ep.getNamedChild("response", false); + Element fullUrl = ep.getNamedChild(FULL_URL, false); Element method = null; Element url = null; if (req != null) { - method = req.getNamedChild("method"); - url = req.getNamedChild("url"); + method = req.getNamedChild("method", false); + url = req.getNamedChild("url", false); } if (resp != null) { return IdStatus.OPTIONAL; @@ -6840,7 +6840,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean IsExemptInvariant(String path, Element element, ElementDefinitionConstraintComponent inv) { if ("eld-24".equals(inv.getKey())) { - String p = element.getNamedChildValue("path"); + String p = element.getNamedChildValue("path", false); return (p != null) && ((p.endsWith("xtension.url") || p.endsWith(".id"))); } return false; @@ -6883,13 +6883,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // todo: validate everything in this bundle. } if (rok) { - if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID) == null)) { + if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID, false) == null)) { ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_MISSING) && ok; - } else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild(ID) != null)) { + } else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild(ID, false) != null)) { ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_PROHIBITED) && ok; } - if (element.getNamedChild(ID) != null) { - Element eid = element.getNamedChild(ID); + if (element.getNamedChild(ID, false) != null) { + Element eid = element.getNamedChild(ID, false); if (eid.getProperty() != null && eid.getProperty().getDefinition() != null && eid.getProperty().getDefinition().getBase().getPath().equals("Resource.id")) { NodeStack ns = stack.push(eid, -1, eid.getProperty().getDefinition(), null); if (eid.primitiveValue() != null && eid.primitiveValue().length() > 64) { @@ -6958,7 +6958,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat bundle.getElement().getNamedChildren(ENTRY, list); if (list.isEmpty()) return null; - Element resource = list.get(0).getNamedChild(RESOURCE); + Element resource = list.get(0).getNamedChild(RESOURCE, false); if (resource == null) return null; else { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java index f040223e0..28af98ece 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java @@ -69,7 +69,7 @@ public class BundleValidator extends BaseValidator { public boolean validateBundle(List errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) { boolean ok = true; - String type = bundle.getNamedChildValue(TYPE); + String type = bundle.getNamedChildValue(TYPE, false); type = StringUtils.defaultString(type); List entries = new ArrayList(); bundle.getNamedChildren(ENTRY, entries); @@ -91,12 +91,12 @@ public class BundleValidator extends BaseValidator { // Get the stack of the first entry NodeStack firstStack = stack.push(firstEntry, 1, null, null); - String fullUrl = firstEntry.getNamedChildValue(FULL_URL); + String fullUrl = firstEntry.getNamedChildValue(FULL_URL, false); if (type.equals(DOCUMENT)) { - Element resource = firstEntry.getNamedChild(RESOURCE); + Element resource = firstEntry.getNamedChild(RESOURCE, false); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) { - String id = resource.getNamedChildValue(ID); + String id = resource.getNamedChildValue(ID, false); ok = validateDocument(errors, bundle, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok; } if (!VersionUtilities.isThisOrLater(FHIRVersion._4_0_1.getDisplay(), bundle.getProperty().getStructure().getFhirVersion().getDisplay())) { @@ -104,9 +104,9 @@ public class BundleValidator extends BaseValidator { } ok = checkAllInterlinked(errors, entries, stack, bundle, false) && ok; } else if (type.equals(MESSAGE)) { - Element resource = firstEntry.getNamedChild(RESOURCE); + Element resource = firstEntry.getNamedChild(RESOURCE, false); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) { - String id = resource.getNamedChildValue(ID); + String id = resource.getNamedChildValue(ID, false); ok = validateMessage(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok; ok = checkAllInterlinked(errors, entries, stack, bundle, true) && ok; } @@ -124,7 +124,7 @@ public class BundleValidator extends BaseValidator { for (Element entry : entries) { NodeStack estack = stack.push(entry, count, null, null); - String fullUrl = entry.getNamedChildValue(FULL_URL); + String fullUrl = entry.getNamedChildValue(FULL_URL, false); String url = getCanonicalURLForEntry(entry); String id = getIdForEntry(entry); String rtype = getTypeForEntry(entry); @@ -146,7 +146,7 @@ public class BundleValidator extends BaseValidator { if (url != null) { if (!(!url.equals(fullUrl) || (url.matches(urlRegex) && url.endsWith("/" + id))) && !isV3orV2Url(url)) ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id) && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild(RESOURCE).fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl) && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild(RESOURCE, false).fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl) && ok; } if (!VersionUtilities.isR2Ver(context.getVersion())) { @@ -156,7 +156,7 @@ public class BundleValidator extends BaseValidator { if (rtype != null) { int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0; counter.put(rtype, rcount); - Element res = entry.getNamedChild(RESOURCE); + Element res = entry.getNamedChild(RESOURCE, false); NodeStack rstack = estack.push(res, -1, null, null); for (BundleValidationRule bvr : validator().getBundleValidationRules()) { if (meetsRule(bvr, rtype, rcount, count)) { @@ -207,7 +207,7 @@ public class BundleValidator extends BaseValidator { private boolean validateDocumentLink(List errors, Element bundle, List links, Element link, NodeStack stack, List entries) { boolean ok = true; - Element relE = link.getNamedChild("relation"); + Element relE = link.getNamedChild("relation", false); if (relE != null) { NodeStack relStack = stack.push(relE, -1, null, null); String rel = relE.getValue(); @@ -216,7 +216,7 @@ public class BundleValidator extends BaseValidator { ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok; } if ("stylesheet".equals(rel)) { - Element urlE = link.getNamedChild("url"); + Element urlE = link.getNamedChild("url", false); if (urlE != null) { NodeStack urlStack = stack.push(urlE, -1, null, null); String url = urlE.getValue(); @@ -238,7 +238,7 @@ public class BundleValidator extends BaseValidator { // has to resolve in the bundle boolean found = false; for (Element e : entries) { - Element res = e.getNamedChild("resource"); + Element res = e.getNamedChild(RESOURCE, false); if (res != null && (""+res.fhirType()+"/"+res.getIdBase()).equals(url)) { found = true; break; @@ -255,7 +255,7 @@ public class BundleValidator extends BaseValidator { private boolean validateMessageLink(List errors, Element bundle, List links, Element link, NodeStack stack, List entries) { boolean ok = true; - Element relE = link.getNamedChild("relation"); + Element relE = link.getNamedChild("relation", false); if (relE != null) { NodeStack relStack = stack.push(relE, -1, null, null); String rel = relE.getValue(); @@ -268,7 +268,7 @@ public class BundleValidator extends BaseValidator { } private boolean validateSearchLink(List errors, Element bundle, List links, Element link, NodeStack stack) { - String rel = StringUtils.defaultString(link.getNamedChildValue("relation")); + String rel = StringUtils.defaultString(link.getNamedChildValue("relation", false)); if (Utilities.existsInList(rel, "first", "previous", "next", "last", "self")) { return rule(errors, "2022-12-09", IssueType.INVALID, link.line(), link.col(), stack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel); } else { @@ -278,7 +278,7 @@ public class BundleValidator extends BaseValidator { private boolean relationshipUnique(String rel, Element link, List links) { for (Element l : links) { - if (l != link && rel.equals(l.getNamedChildValue("relation"))) { + if (l != link && rel.equals(l.getNamedChildValue("relation", false))) { return false; } if (l == link) { @@ -291,7 +291,7 @@ public class BundleValidator extends BaseValidator { private boolean validateCollectionLink(List errors, Element bundle, List links, Element link, NodeStack stack) { boolean ok = true; - Element relE = link.getNamedChild("relation"); + Element relE = link.getNamedChild("relation", false); if (relE != null) { NodeStack relStack = stack.push(relE, -1, null, null); String rel = relE.getValue(); @@ -305,7 +305,7 @@ public class BundleValidator extends BaseValidator { private boolean validateSubscriptionLink(List errors, Element bundle, List links, Element link, NodeStack stack) { boolean ok = true; - Element relE = link.getNamedChild("relation"); + Element relE = link.getNamedChild("relation", false); if (relE != null) { NodeStack relStack = stack.push(relE, -1, null, null); String rel = relE.getValue(); @@ -319,7 +319,7 @@ public class BundleValidator extends BaseValidator { private boolean validateTransactionOrBatchLink(List errors, Element bundle, List links, Element link, NodeStack stack) { boolean ok = true; - Element relE = link.getNamedChild("relation"); + Element relE = link.getNamedChild("relation", false); if (relE != null) { NodeStack relStack = stack.push(relE, -1, null, null); String rel = relE.getValue(); @@ -342,7 +342,7 @@ public class BundleValidator extends BaseValidator { if (selfLink == null) { warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_NOSELF); } else { - readSearchResourceTypes(selfLink.getNamedChildValue("url"), types); + readSearchResourceTypes(selfLink.getNamedChildValue("url", false), types); if (types.size() == 0) { hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_SELF_NOT_UNDERSTOOD); } @@ -356,7 +356,7 @@ public class BundleValidator extends BaseValidator { for (Element entry : entries) { NodeStack estack = stack.push(entry, count, null, null); count++; - Element res = entry.getNamedChild("resource"); + Element res = entry.getNamedChild(RESOURCE, false); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) { NodeStack rstack = estack.push(res, -1, null, null); String rt = res.fhirType(); @@ -364,11 +364,11 @@ public class BundleValidator extends BaseValidator { if (bok == null) { typeProblem = true; hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), selfLink == null, I18nConstants.BUNDLE_SEARCH_ENTRY_TYPE_NOT_SURE); - String id = res.getNamedChildValue("id"); + String id = res.getNamedChildValue("id", false); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null || "OperationOutcome".equals(rt), I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID); } else if (bok) { if (!"OperationOutcome".equals(rt)) { - String id = res.getNamedChildValue("id"); + String id = res.getNamedChildValue("id", false); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID); if (rtype != null && !rt.equals(rtype)) { typeProblem = true; @@ -394,17 +394,17 @@ public class BundleValidator extends BaseValidator { for (Element entry : entries) { NodeStack estack = stack.push(entry, count, null, null); count++; - Element res = entry.getNamedChild("resource"); + Element res = entry.getNamedChild(RESOURCE, false); String sm = null; - Element s = entry.getNamedChild("search"); + Element s = entry.getNamedChild("search", false); if (s != null) { - sm = s.getNamedChildValue("mode"); + sm = s.getNamedChildValue("mode", false); } warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), sm != null, I18nConstants.BUNDLE_SEARCH_NO_MODE); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) { NodeStack rstack = estack.push(res, -1, null, null); String rt = res.fhirType(); - String id = res.getNamedChildValue("id"); + String id = res.getNamedChildValue("id", false); if (sm != null) { if ("match".equals(sm)) { ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID) && ok; @@ -436,9 +436,9 @@ public class BundleValidator extends BaseValidator { boolean any = false; for (Element entry : entries) { String sm = null; - Element s = entry.getNamedChild("search"); + Element s = entry.getNamedChild("search", false); if (s != null) { - sm = s.getNamedChildValue("mode"); + sm = s.getNamedChildValue("mode", false); } if (sm != null) { any = true; @@ -484,7 +484,7 @@ public class BundleValidator extends BaseValidator { private Element getSelfLink(List links) { for (Element link : links) { - if ("self".equals(link.getNamedChildValue("relation"))) { + if ("self".equals(link.getNamedChildValue("relation", false))) { return link; } } @@ -582,7 +582,7 @@ public class BundleValidator extends BaseValidator { private boolean validateBundleReference(List errors, Element bundle, List entries, Element ref, String name, NodeStack stack, String fullUrl, String type, String id) { String reference = null; try { - reference = ref.getNamedChildValue("reference"); + reference = ref.getNamedChildValue("reference", false); } catch (Error e) { } @@ -610,9 +610,9 @@ public class BundleValidator extends BaseValidator { * @param stack {@link NodeStack} */ private boolean handleSpecialCaseForLastUpdated(Element bundle, List errors, NodeStack stack) { - boolean ok = bundle.hasChild(META) - && bundle.getNamedChild(META).hasChild(LAST_UPDATED) - && bundle.getNamedChild(META).getNamedChild(LAST_UPDATED).hasValue(); + boolean ok = bundle.hasChild(META, false) + && bundle.getNamedChild(META, false).hasChild(LAST_UPDATED, false) + && bundle.getNamedChild(META, false).getNamedChild(LAST_UPDATED, false).hasValue(); ruleHtml(errors, NO_RULE_DATE, IssueType.REQUIRED, stack.getLiteralPath(), ok, I18nConstants.DOCUMENT_DATE_REQUIRED, I18nConstants.DOCUMENT_DATE_REQUIRED_HTML); return ok; } @@ -622,7 +622,7 @@ public class BundleValidator extends BaseValidator { List entryList = new ArrayList<>(); int i = 0; for (Element entry : entries) { - Element r = entry.getNamedChild(RESOURCE); + Element r = entry.getNamedChild(RESOURCE, false); if (r != null) { EntrySummary e = new EntrySummary(i, entry, r); entryList.add(e); @@ -705,8 +705,8 @@ public class BundleValidator extends BaseValidator { private void visitBundleLinks(Set visited, List entryList, Element bundle) { List links = bundle.getChildrenByName("link"); for (Element link : links) { - String rel = link.getNamedChildValue("relation"); - String url = link.getNamedChildValue("url"); + String rel = link.getNamedChildValue("relation", false); + String url = link.getNamedChildValue("url", false); if (rel != null && url != null) { if (Utilities.existsInList(rel, "stylesheet")) { for (EntrySummary e : entryList) { @@ -727,21 +727,21 @@ public class BundleValidator extends BaseValidator { } private String getCanonicalURLForEntry(Element entry) { - Element e = entry.getNamedChild(RESOURCE); + Element e = entry.getNamedChild(RESOURCE, false); if (e == null) return null; - return e.getNamedChildValue("url"); + return e.getNamedChildValue("url", false); } private String getIdForEntry(Element entry) { - Element e = entry.getNamedChild(RESOURCE); + Element e = entry.getNamedChild(RESOURCE, false); if (e == null) return null; - return e.getNamedChildValue(ID); + return e.getNamedChildValue(ID, false); } private String getTypeForEntry(Element entry) { - Element e = entry.getNamedChild(RESOURCE); + Element e = entry.getNamedChild(RESOURCE, false); if (e == null) return null; return e.fhirType(); @@ -760,9 +760,9 @@ public class BundleValidator extends BaseValidator { // TODO: Need to handle _version int i = 1; for (Element entry : entries) { - String fullUrl = entry.getNamedChildValue(FULL_URL); - Element resource = entry.getNamedChild(RESOURCE); - String id = resource != null ? resource.getNamedChildValue(ID) : null; + String fullUrl = entry.getNamedChildValue(FULL_URL, false); + Element resource = entry.getNamedChild(RESOURCE, false); + String id = resource != null ? resource.getNamedChildValue(ID, false) : null; if (id != null && fullUrl != null) { String urlId = null; if (fullUrl.startsWith("https://") || fullUrl.startsWith("http://")) { @@ -801,7 +801,7 @@ public class BundleValidator extends BaseValidator { // // private boolean followResourceLinks(Element entry, Map visitedResources, Map candidateEntries, List candidateResources, List errors, NodeStack stack, int depth) { // boolean ok = true; -// Element resource = entry.getNamedChild(RESOURCE); +// Element resource = entry.getNamedChild(RESOURCE, false); // if (visitedResources.containsValue(resource)) // return ok; // diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java index e2aae0ea0..ecae9ad0b 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java @@ -29,16 +29,16 @@ public class CodeSystemValidator extends BaseValidator { public boolean validateCodeSystem(List errors, Element cs, NodeStack stack, ValidationOptions options) { boolean ok = true; - String url = cs.getNamedChildValue("url"); - String content = cs.getNamedChildValue("content"); - String caseSensitive = cs.getNamedChildValue("caseSensitive"); - String hierarchyMeaning = cs.getNamedChildValue("hierarchyMeaning"); - String supp = cs.getNamedChildValue("supplements"); + String url = cs.getNamedChildValue("url", false); + String content = cs.getNamedChildValue("content", false); + String caseSensitive = cs.getNamedChildValue("caseSensitive", false); + String hierarchyMeaning = cs.getNamedChildValue("hierarchyMeaning", false); + String supp = cs.getNamedChildValue("supplements", false); int count = countConcepts(cs); metaChecks(errors, cs, stack, url, content, caseSensitive, hierarchyMeaning, !Utilities.noString(supp), count, supp); - String vsu = cs.getNamedChildValue("valueSet"); + String vsu = cs.getNamedChildValue("valueSet", false); if (!Utilities.noString(vsu)) { hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE); ValueSet vs; @@ -98,29 +98,29 @@ public class CodeSystemValidator extends BaseValidator { if (parent.isForPublication()) { if (isHL7(cs)) { boolean ok = true; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "url") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "version") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "title") && ok; - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7, "name"); - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "status") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "experimental") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "description") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "content") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "url") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "version") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "title") && ok; + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7, "name"); + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "status") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "experimental") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "description") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "content") && ok; if (!"supplement".equals(cs.getChildValue("content"))) { - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "caseSensitive") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "caseSensitive") && ok; } return ok; } else { - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "url"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "version"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "title"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING, "name"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "status"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "experimental"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "description"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "content"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "url"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "version"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "title"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING, "name"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "status"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "experimental"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "description"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "content"); if (!"supplement".equals(cs.getChildValue("content"))) { - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "caseSensitive"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "caseSensitive"); } } } @@ -130,15 +130,15 @@ public class CodeSystemValidator extends BaseValidator { private void metaChecks(List errors, Element cs, NodeStack stack, String url, String content, String caseSensitive, String hierarchyMeaning, boolean isSupplement, int count, String supp) { if (isSupplement) { if (!"supplement".equals(content)) { - NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); + NodeStack s = stack.push(cs.getNamedChild("content", false), -1, null, null); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG); } if (!Utilities.noString(caseSensitive)) { - NodeStack s = stack.push(cs.getNamedChild("caseSensitive"), -1, null, null); + NodeStack s = stack.push(cs.getNamedChild("caseSensitive", false), -1, null, null); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive"); } if (!Utilities.noString(hierarchyMeaning)) { - NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning"), -1, null, null); + NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning", false), -1, null, null); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "hierarchyMeaning"); } @@ -146,7 +146,7 @@ public class CodeSystemValidator extends BaseValidator { boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org")); if (Utilities.noString(content)) { NodeStack s = stack; - Element c = cs.getNamedChild("content"); + Element c = cs.getNamedChild("content", false); if (c != null) { s = stack.push(c, -1, null, null); } @@ -156,12 +156,12 @@ public class CodeSystemValidator extends BaseValidator { warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "content"); } } else if ("supplement".equals(content)) { - NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); + NodeStack s = stack.push(cs.getNamedChild("content", false), -1, null, null); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING); } if (Utilities.noString(caseSensitive)) { NodeStack s = stack; - Element c = cs.getNamedChild("caseSensitive"); + Element c = cs.getNamedChild("caseSensitive", false); if (c != null) { s = stack.push(c, -1, null, null); } @@ -173,7 +173,7 @@ public class CodeSystemValidator extends BaseValidator { } if (Utilities.noString(hierarchyMeaning) && hasHeirarchy(cs)) { NodeStack s = stack; - Element c = cs.getNamedChild("hierarchyMeaning"); + Element c = cs.getNamedChild("hierarchyMeaning", false); if (c != null) { s = stack.push(c, -1, null, null); } @@ -185,10 +185,10 @@ public class CodeSystemValidator extends BaseValidator { } } - if (cs.hasChild("count")) { - int statedCount = Utilities.parseInt(cs.getNamedChildValue("count"), -1); + if (cs.hasChild("count", false)) { + int statedCount = Utilities.parseInt(cs.getNamedChildValue("count", false), -1); if (statedCount > -1 && content != null) { // error elsewhere - var nstack = stack.push(cs.getNamedChild("count"), -1, null, null); + var nstack = stack.push(cs.getNamedChild("count", false), -1, null, null); switch (content) { case "complete": rule(errors, "2023-08-15", IssueType.INVALID, nstack, count == statedCount, I18nConstants.CODESYSTEM_CS_COUNT_COMPLETE_WRONG, count, statedCount); @@ -199,7 +199,7 @@ public class CodeSystemValidator extends BaseValidator { break; case "not-present": if (cs.hasChildren("concept")) { - hint(errors, "2023-08-15", IssueType.INVALID, stack.push(cs.getNamedChild("concept"), -1, null, null), statedCount > 0, I18nConstants.CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO, statedCount); + hint(errors, "2023-08-15", IssueType.INVALID, stack.push(cs.getNamedChild("concept", false), -1, null, null), statedCount > 0, I18nConstants.CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO, statedCount); } break; case "supplement": diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java index d2a5b5bd9..fcd332483 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ConceptMapValidator.java @@ -187,13 +187,13 @@ public class ConceptMapValidator extends BaseValidator { private VSReference readVSReference(Element cm, String... names) { for (String n : names) { - if (cm.hasChild(n)) { - Element e = cm.getNamedChild(n); + if (cm.hasChild(n, false)) { + Element e = cm.getNamedChild(n, false); String ref = null; if (e.isPrimitive()) { ref = e.primitiveValue(); - } else if (e.hasChild("reference")) { - ref = e.getNamedChildValue("reference"); + } else if (e.hasChild("reference", false)) { + ref = e.getNamedChildValue("reference", false); } if (ref != null) { VSReference res = new VSReference(); @@ -218,9 +218,9 @@ public class ConceptMapValidator extends BaseValidator { ctxt.sourceScope = sourceScope; ctxt.targetScope = targetScope; - Element e = grp.getNamedChild("source"); + Element e = grp.getNamedChild("source", false); if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_MISSING)) { - ctxt.source = readCSReference(e, grp.getNamedChild("sourceVersion")); + ctxt.source = readCSReference(e, grp.getNamedChild("sourceVersion", false)); if (ctxt.source.cs != null) { if (ctxt.source.cs.getContent() == CodeSystemContentMode.NOTPRESENT) { ctxt.source.cs = null; @@ -231,9 +231,9 @@ public class ConceptMapValidator extends BaseValidator { warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), sourceScope != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_UNKNOWN, e.getValue()); } } - e = grp.getNamedChild("target"); + e = grp.getNamedChild("target", false); if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_MISSING)) { - ctxt.target = readCSReference(e, grp.getNamedChild("targetVersion")); + ctxt.target = readCSReference(e, grp.getNamedChild("targetVersion", false)); if (ctxt.target.cs != null) { if (ctxt.target.cs.getContent() == CodeSystemContentMode.NOTPRESENT) { ctxt.target.cs = null; @@ -274,14 +274,14 @@ public class ConceptMapValidator extends BaseValidator { private boolean validateGroupElement(List errors, Element src, NodeStack stack, Map props, Map attribs, ValidationOptions options, GroupContext ctxt) { boolean ok = true; - Element code = src.getNamedChild("code"); + Element code = src.getNamedChild("code", false); if (code != null) { NodeStack cstack = stack.push(code, -1, null, null); if (ctxt.hasSourceCS()) { String c = code.getValue(); ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.source.cs, c); if (warningOrError(ctxt.source.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_CODE_INVALID, c, ctxt.source.cs.getVersionedUrl())) { - Element display = src.getNamedChild("display"); + Element display = src.getNamedChild("display", false); if (display != null) { warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.source.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_SOURCE_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.source.cs, cd)); } @@ -311,14 +311,14 @@ public class ConceptMapValidator extends BaseValidator { private boolean validateGroupElementTarget(List errors, Element tgt, NodeStack stack, Map props, Map attribs, ValidationOptions options, GroupContext ctxt) { boolean ok = true; - Element code = tgt.getNamedChild("code"); + Element code = tgt.getNamedChild("code", false); if (code != null) { NodeStack cstack = stack.push(code, -1, null, null); if (ctxt.hasTargetCS()) { String c = code.getValue(); ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.target.cs, c); if (warningOrError(ctxt.target.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_CODE_INVALID, c, ctxt.target.cs.getVersionedUrl())) { - Element display = tgt.getNamedChild("display"); + Element display = tgt.getNamedChild("display", false); if (display != null) { warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.target.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_TARGET_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.target.cs, cd)); } @@ -362,8 +362,8 @@ public class ConceptMapValidator extends BaseValidator { private boolean validateGroupElementTargetProperty(List errors, Element property, NodeStack stack, Map props) { boolean ok = true; - Element codeE = property.getNamedChild("code"); - Element valueE = property.getNamedChild("value"); + Element codeE = property.getNamedChild("code", false); + Element valueE = property.getNamedChild("value", false); String code = codeE.getValue(); if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), props.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, props.keySet())) { PropertyDefinition defn = props.get(code); @@ -388,8 +388,8 @@ public class ConceptMapValidator extends BaseValidator { private boolean validateGroupElementTargetAttribute(List errors, Element attribute, NodeStack stack, Map attribs) { boolean ok = true; - Element codeE = attribute.getNamedChild("attribute"); - Element valueE = attribute.getNamedChild("value"); + Element codeE = attribute.getNamedChild("attribute", false); + Element valueE = attribute.getNamedChild("value", false); String code = codeE.getValue(); if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), attribs.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, attribs.keySet())) { NodeStack stackV = stack.push(valueE, -1, null, null); @@ -404,22 +404,22 @@ public class ConceptMapValidator extends BaseValidator { if (parent.isForPublication()) { if (isHL7(cs)) { boolean ok = true; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "url") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "version") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "title") && ok; - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7, "name"); - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "status") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "experimental") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "description") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "url") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "version") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "title") && ok; + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7, "name"); + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "status") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "experimental") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "description") && ok; return ok; } else { - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "url"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "version"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "title"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING, "name"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "status"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "experimental"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "description"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "url"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "version"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "title"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING, "name"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "status"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "experimental"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "description"); } } return true; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java index af2628d76..314e2009d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/MeasureValidator.java @@ -62,22 +62,22 @@ public class MeasureValidator extends BaseValidator { int c = 0; for (Element group : groups) { NodeStack ns = stack.push(group, c, null, null); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), groups.size() ==1 || group.hasChild("code"), I18nConstants.MEASURE_M_GROUP_CODE); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), groups.size() ==1 || group.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_CODE); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), group.hasChildren("population"), I18nConstants.MEASURE_M_GROUP_POP); int c1 = 0; List pl = group.getChildrenByName("population"); for (Element p : pl) { NodeStack ns2 = ns.push(p, c1, null, null); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, p.line(), p.col(), ns2.getLiteralPath(), pl.size() == 1 || p.hasChild("code"), I18nConstants.MEASURE_M_GROUP_POP_NO_CODE); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, p.line(), p.col(), ns2.getLiteralPath(), pl.size() == 1 || p.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_POP_NO_CODE); c1++; } c1 = 0; List stl = group.getChildrenByName("stratifier"); for (Element st : stl) { NodeStack ns2 = ns.push(st, c1, null, null); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, st.line(), st.col(), ns2.getLiteralPath(), stl.size() == 1 || st.hasChild("code"), I18nConstants.MEASURE_M_GROUP_STRATA_NO_CODE); - if (st.hasChild("criteria")) { - Element crit = st.getNamedChild("criteria"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, st.line(), st.col(), ns2.getLiteralPath(), stl.size() == 1 || st.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_STRATA_NO_CODE); + if (st.hasChild("criteria", false)) { + Element crit = st.getNamedChild("criteria", false); NodeStack nsc = ns2.push(crit, -1, null, null); ok = validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok; } @@ -85,9 +85,9 @@ public class MeasureValidator extends BaseValidator { List cpl = group.getChildrenByName("component"); for (Element cp : cpl) { NodeStack ns3 = ns2.push(cp, c2, null, null); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cp.line(), cp.col(), ns3.getLiteralPath(), cpl.size() == 1 || cp.hasChild("code"), I18nConstants.MEASURE_M_GROUP_STRATA_COMP_NO_CODE); - if (cp.hasChild("criteria")) { - Element crit = cp.getNamedChild("criteria"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cp.line(), cp.col(), ns3.getLiteralPath(), cpl.size() == 1 || cp.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_STRATA_COMP_NO_CODE); + if (cp.hasChild("criteria", false)) { + Element crit = cp.getNamedChild("criteria", false); NodeStack nsc = ns3.push(crit, -1, null, null); ok= validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok; } @@ -109,23 +109,23 @@ public class MeasureValidator extends BaseValidator { boolean ok = true; if (parent.isForPublication()) { if (isHL7(cs)) { - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "url") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "version") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING_HL7, "name") && ok; - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "title"); - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "status") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "experimental") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "publisher") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "description") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "url") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "version") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING_HL7, "name") && ok; + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "title"); + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "status") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "experimental") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "publisher") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "description") && ok; } else { - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING, "url"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING, "version"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING, "name"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING, "title"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING, "status"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING, "experimental"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING, "description"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher"), I18nConstants.MEASURE_SHAREABLE_MISSING, "publisher"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "url"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "version"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING, "name"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "title"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "status"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "experimental"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "description"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "publisher"); } } return ok; @@ -208,7 +208,7 @@ public class MeasureValidator extends BaseValidator { public boolean validateMeasureReport(ValidationContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { boolean ok = true; - Element m = element.getNamedChild("measure"); + Element m = element.getNamedChild("measure", false); String measure = null; if (m != null) { /* @@ -228,7 +228,7 @@ public class MeasureValidator extends BaseValidator { Measure msrc = measure.startsWith("#") ? loadMeasure(element, measure.substring(1)) : context.fetchResource(Measure.class, measure); timeTracker.sd(t); if (warning(errors, NO_RULE_DATE, IssueType.REQUIRED, m.line(), m.col(), stack.getLiteralPath(), msrc != null, I18nConstants.MEASURE_MR_M_NOTFOUND, measure)) { - boolean inComplete = !"complete".equals(element.getNamedChildValue("status")); + boolean inComplete = !"complete".equals(element.getNamedChildValue("status", false)); MeasureContext mc = new MeasureContext(msrc, element); NodeStack ns = stack.push(m, -1, m.getProperty().getDefinition(), m.getProperty().getDefinition()); hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, m.line(), m.col(), ns.getLiteralPath(), Utilities.existsInList(mc.scoring(), "proportion", "ratio", "continuous-variable", "cohort"), I18nConstants.MEASURE_MR_M_SCORING_UNK); @@ -299,8 +299,8 @@ public class MeasureValidator extends BaseValidator { // but we still check that the code, if both have one, is consistent. Element mrg = glist.get(0); NodeStack ns = stack.push(mrg, 0, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition()); - if (m.groups().get(0).hasCode() && mrg.hasChild("code")) { - CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code")); + if (m.groups().get(0).hasCode() && mrg.hasChild("code", false)) { + CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code", false)); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), hasUseableCode(cc), I18nConstants.MEASURE_MR_GRP_NO_USABLE_CODE)) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc.matches(m.groups().get(0).getCode()), I18nConstants.MEASURE_MR_GRP_NO_WRONG_CODE, DataRenderer.display(context, cc), DataRenderer.display(context, m.groups().get(0).getCode())) && ok; } else { @@ -312,7 +312,7 @@ public class MeasureValidator extends BaseValidator { int i = 0; for (Element mrg : glist) { NodeStack ns = stack.push(mrg, i, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition()); - CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code")); + CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code", false)); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_NO_CODE)) { MeasureGroupComponent mg = getGroupForCode(cc, m.measure()); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mg != null, I18nConstants.MEASURE_MR_GRP_UNK_CODE)) { @@ -355,7 +355,7 @@ public class MeasureValidator extends BaseValidator { private boolean validateScore(ValidationContext hostContext, MeasureContext m, List errors, Element mrg, NodeStack stack, boolean inProgress) { boolean ok = true; - Element ms = mrg.getNamedChild("measureScore"); + Element ms = mrg.getNamedChild("measureScore", false); // first, we check MeasureReport.type if ("data-collection".equals(m.reportType())) { ok = banned(errors, stack, ms, I18nConstants.MEASURE_MR_SCORE_PROHIBITED_RT) && ok; @@ -365,11 +365,11 @@ public class MeasureValidator extends BaseValidator { } else if (Utilities.existsInList(m.scoring(), "proportion", "ratio", "continuous-variable")) { if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, mrg.line(), mrg.col(), stack.getLiteralPath(), ms != null, I18nConstants.MEASURE_MR_SCORE_REQUIRED, m.scoring())) { NodeStack ns = stack.push(ms, -1, ms.getProperty().getDefinition(), ms.getProperty().getDefinition()); - Element v = ms.getNamedChild("value"); + Element v = ms.getNamedChild("value", false); // TODO: this is a DEQM special and should be handled differently if (v == null) { if (ms.hasExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType")) { - v = ms.getExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType").getNamedChild("value"); + v = ms.getExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType").getNamedChild("value", false); } } if ("proportion".equals(m.scoring())) { @@ -391,13 +391,13 @@ public class MeasureValidator extends BaseValidator { } else if ("ratio".equals(m.scoring())) { // ratio - score is a number with no value constraints, and maybe with a unit (perhaps constrained by extension) if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "ratio")) { - Element unit = ms.getNamedChild("code"); + Element unit = ms.getNamedChild("code", false); Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null; if (unit != null) { if (c != null) { NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition()); ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode()) && ok; - Element system = ms.getNamedChild("system"); + Element system = ms.getNamedChild("system", false); if (system == null) { NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition()); ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok; @@ -416,13 +416,13 @@ public class MeasureValidator extends BaseValidator { } else if ("continuous-variable".equals(m.scoring())) { // continuous-variable - score is a quantity with a unit per the extension if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "continuous-variable")) { - Element unit = ms.getNamedChild("code"); + Element unit = ms.getNamedChild("code", false); Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null; if (unit != null) { if (c != null) { NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition()); rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode()); - Element system = ms.getNamedChild("system"); + Element system = ms.getNamedChild("system", false); if (system == null) { NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition()); ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok; @@ -443,7 +443,7 @@ public class MeasureValidator extends BaseValidator { } private boolean banned(List errors, NodeStack stack, Element parent, String childName, String msgId, Object... params) { - Element child = parent.getNamedChild(childName); + Element child = parent.getNamedChild(childName, false); return banned(errors, stack, child, msgId, params); } @@ -465,7 +465,7 @@ public class MeasureValidator extends BaseValidator { int i = 0; for (Element mrgp : plist) { NodeStack ns = stack.push(mrgp, i, mrgp.getProperty().getDefinition(), mrgp.getProperty().getDefinition()); - CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgp.getNamedChild("code")); + CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgp.getNamedChild("code", false)); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) { MeasureGroupPopulationComponent mgp = getGroupPopForCode(cc, mg); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgp != null, I18nConstants.MEASURE_MR_GRP_POP_UNK_CODE)) { @@ -503,7 +503,7 @@ public class MeasureValidator extends BaseValidator { } } else { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), sr.size() == 0, I18nConstants.MEASURE_MR_GRP_POP_NO_SUBJECTS) && ok; - warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), mrgp.hasChild("count"), I18nConstants.MEASURE_MR_GRP_POP_NO_COUNT); + warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), mrgp.hasChild("count", false), I18nConstants.MEASURE_MR_GRP_POP_NO_COUNT); } return ok; } @@ -518,7 +518,7 @@ public class MeasureValidator extends BaseValidator { int i = 0; for (Element mrgs : slist) { NodeStack ns = stack.push(mrgs, i, mrgs.getProperty().getDefinition(), mrgs.getProperty().getDefinition()); - CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgs.getNamedChild("code")); + CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgs.getNamedChild("code", false)); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgs.line(), mrgs.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) { MeasureGroupStratifierComponent mgs = getGroupStratifierForCode(cc, mg); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgs != null, I18nConstants.MEASURE_MR_GRPST_POP_UNK_CODE)) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ObservationValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ObservationValidator.java index 08efb4d51..3f82f0652 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ObservationValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ObservationValidator.java @@ -29,18 +29,18 @@ public class ObservationValidator extends BaseValidator { boolean ok = true; // all observations should have a subject, a performer, and a time - ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), element.getNamedChild("subject") != null, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_SUBJECT) && ok; + ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), element.getNamedChild("subject", false) != null, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_SUBJECT) && ok; List performers = new ArrayList<>(); element.getNamedChildren("performer", performers); ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), performers.size() > 0, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_PERFORMER) && ok; ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), - element.getNamedChild("effectiveDateTime") != null || element.getNamedChild("effectivePeriod") != null || - element.getNamedChild("effectiveTiming") != null || element.getNamedChild("effectiveInstant") != null, + element.getNamedChild("effectiveDateTime", false) != null || element.getNamedChild("effectivePeriod", false) != null || + element.getNamedChild("effectiveTiming", false) != null || element.getNamedChild("effectiveInstant", false) != null, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok; // hook in the vital signs if (VersionUtilities.isR4Plus(context.getVersion())) { - Element code = element.getNamedChild("code"); + Element code = element.getNamedChild("code", false); List codes = new ArrayList<>(); if (hasLoincCode(code, codes, "85353-1")) { ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes, pct, mode) && ok; @@ -102,8 +102,8 @@ public class ObservationValidator extends BaseValidator { if (code != null) { List codings = code.getChildren("coding"); for (Element coding : codings) { - if ("http://loinc.org".equals(coding.getNamedChildValue("system")) && Utilities.existsInList(coding.getNamedChildValue("code"), values)) { - codes.add(coding.getNamedChildValue("code")); + if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) { + codes.add(coding.getNamedChildValue("code", false)); return true; } } @@ -115,8 +115,8 @@ public class ObservationValidator extends BaseValidator { if (code != null) { List codings = code.getChildren("coding"); for (Element coding : codings) { - if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system")) && Utilities.existsInList(coding.getNamedChildValue("code"), values)) { - codes.add(coding.getNamedChildValue("code")); + if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) { + codes.add(coding.getNamedChildValue("code", false)); return true; } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index bde4fcfa4..ebb55a0c3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -154,11 +154,11 @@ public class QuestionnaireValidator extends BaseValidator { Element ext = e.getExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-derivationType"); if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, ext != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE, url)) { NodeStack next = ns.push(ext, -1, ext.getProperty().getDefinition(), ext.getProperty().getDefinition()); - Element v = ext.getNamedChild("value"); + Element v = ext.getNamedChild("value", false); if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, next, v != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE_VALUE)) { NodeStack nv = next.push(v, -1, v.getProperty().getDefinition(), v.getProperty().getDefinition()); - String s = v.getNamedChildValue("system"); - String c = v.getNamedChildValue("code"); + String s = v.getNamedChildValue("system", false); + String c = v.getNamedChildValue("code", false); if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "extends".equals(c)) { derivations.add(new QuestionnaireDerivation(q, QuestionnaireDerivationMode.EXTENDS)); } else if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "compliesWith".equals(c)) { @@ -196,7 +196,7 @@ public class QuestionnaireValidator extends BaseValidator { if ((VersionUtilities.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) { List ewl = item.getChildren("enableWhen"); for (Element ew : ewl) { - String ql = ew.getNamedChildValue("question"); + String ql = ew.getNamedChildValue("question", false); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, ql != null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_NOLINK)) { Element tgt = getQuestionById(item, ql); if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, tgt == null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_ISINNER)) { @@ -228,7 +228,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean validateQuestionnaireElementDerivation(List errors, NodeStack ns, Element questionnaire, Element item, QuestionnaireDerivation derivation) { boolean ok = true; - String linkId = item.getNamedChildValue("linkId"); + String linkId = item.getNamedChildValue("linkId", false); QuestionnaireItemComponent qi = derivation.questionnaire.getQuestion(linkId); if (qi == null) { ok = rule(errors, "2023-06-15", IssueType.NOTFOUND, ns.getLiteralPath(), derivation.mode == QuestionnaireDerivationMode.EXTENDS, I18nConstants.QUESTIONNAIRE_Q_ITEM_NOT_DERIVED, derivation.questionnaire.getUrl(), linkId) && ok; @@ -237,7 +237,7 @@ public class QuestionnaireValidator extends BaseValidator { // type must be the same if (qi.hasType()) { - Element e = item.getNamedChild("type"); + Element e = item.getNamedChild("type", false); if (e != null) { NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, qi.getType().toCode().equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_TYPE, derivation.questionnaire.getUrl(), linkId, qi.getType().toCode(), e.primitiveValue()) && ok; @@ -246,7 +246,7 @@ public class QuestionnaireValidator extends BaseValidator { // if it doesn't repeat, it can't start repeating if (!qi.getRepeats()) { - Element e = item.getNamedChild("repeats"); + Element e = item.getNamedChild("repeats", false); if (e != null) { NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, !"true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REPEATS, derivation.questionnaire.getUrl(), linkId) && ok; @@ -255,7 +255,7 @@ public class QuestionnaireValidator extends BaseValidator { // if it is required, it can't become un-required if (qi.getRequired()) { - Element e = item.getNamedChild("required"); + Element e = item.getNamedChild("required", false); if (e != null) { NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REQUIRED, derivation.questionnaire.getUrl(), linkId) && ok; @@ -264,7 +264,7 @@ public class QuestionnaireValidator extends BaseValidator { // if it has a definition, it shouldn't change if (qi.hasDefinition()) { - Element e = item.getNamedChild("definition"); + Element e = item.getNamedChild("definition", false); if (e != null) { NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); hint(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_DEFINITION, derivation.questionnaire.getUrl(), linkId, qi.getDefinition()); @@ -275,7 +275,7 @@ public class QuestionnaireValidator extends BaseValidator { // if it has maxLength, that can't get longer if (qi.hasMaxLength()) { - Element e = item.getNamedChild("maxlength"); + Element e = item.getNamedChild("maxlength", false); if (e != null) { NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); int ml = Utilities.parseInt(e.primitiveValue(), 0); @@ -286,7 +286,7 @@ public class QuestionnaireValidator extends BaseValidator { } if (qi.hasAnswerOption()) { - Element e = item.getNamedChild("answerValueSet"); + Element e = item.getNamedChild("answerValueSet", false); if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "Option", "ValueSet")) { // for each answer option here, there must be a matching answer option in the source List list = new ArrayList<>(); @@ -295,7 +295,7 @@ public class QuestionnaireValidator extends BaseValidator { for (int i = 0; i < list.size(); i++) { Element ao = list.get(i); NodeStack nao = ns.push(ao, i, ao.getProperty().getDefinition(), ao.getProperty().getDefinition()); - Element v = ao.getNamedChild("value"); + Element v = ao.getNamedChild("value", false); if (v != null) { boolean aok = false; switch (v.fhirType()) { @@ -312,10 +312,10 @@ public class QuestionnaireValidator extends BaseValidator { aok = findAOPrimitive(qi.getAnswerOption(), "string", v.primitiveValue()); break; case "Coding": - aok = findAOCoding(qi.getAnswerOption(), new Coding().setSystem(v.getNamedChildValue("system")).setVersion(v.getNamedChildValue("version")).setCode(v.getNamedChildValue("code"))); + aok = findAOCoding(qi.getAnswerOption(), new Coding().setSystem(v.getNamedChildValue("system", false)).setVersion(v.getNamedChildValue("version", false)).setCode(v.getNamedChildValue("code", false))); break; case "Reference": - aok = findAOReference(qi.getAnswerOption(), new Reference().setReference(v.getNamedChildValue("reference"))); + aok = findAOReference(qi.getAnswerOption(), new Reference().setReference(v.getNamedChildValue("reference", false))); break; } ok= rule(errors, "2023-06-15", IssueType.BUSINESSRULE, nao, aok, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_ANSWER_OPTIONS_NEW, derivation.questionnaire.getUrl(), linkId) && ok; @@ -329,7 +329,7 @@ public class QuestionnaireValidator extends BaseValidator { } } if (qi.hasAnswerValueSet()) { - Element e = item.getNamedChild("answerOption"); + Element e = item.getNamedChild("answerOption", false); if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "ValueSet", "Option")) { warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NI_ANSWER_VS, derivation.questionnaire.getUrl(), linkId); } else { @@ -415,7 +415,7 @@ public class QuestionnaireValidator extends BaseValidator { private Element getQuestionById(Element focus, String ql) { List list = getItems(focus); for (Element item : list) { - String v = item.getNamedChildValue("linkId"); + String v = item.getNamedChildValue("linkId", false); if (ql.equals(v)) return item; Element tgt = getQuestionById(item, ql); @@ -437,7 +437,7 @@ public class QuestionnaireValidator extends BaseValidator { return true; } boolean ok = true; - Element q = element.getNamedChild("questionnaire"); + Element q = element.getNamedChild("questionnaire", false); String questionnaire = null; if (q != null) { /* @@ -475,7 +475,7 @@ public class QuestionnaireValidator extends BaseValidator { qok = warning(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); } if (qok) { - boolean inProgress = "in-progress".equals(element.getNamedChildValue("status")); + boolean inProgress = "in-progress".equals(element.getNamedChildValue("status", false)); ok = validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.q().getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element)) && ok; } } @@ -485,7 +485,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean validateQuestionnaireResponseItem(ValidationContext hostContext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { BooleanHolder ok = new BooleanHolder(); - String text = element.getNamedChildValue("text"); + String text = element.getNamedChildValue("text", false); ok.see(rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), I18nConstants.QUESTIONNAIRE_QR_ITEM_TEXT, qItem.getLinkId())); List answers = new ArrayList(); @@ -638,7 +638,7 @@ public class QuestionnaireValidator extends BaseValidator { int lastIndex = -1; int counter = 0; for (Element item : items) { - String linkId = item.getNamedChildValue("linkId"); + String linkId = item.getNamedChildValue("linkId", false); if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), I18nConstants.QUESTIONNAIRE_QR_ITEM_NOLINKID)) { int index = getLinkIdIndex(qItems, linkId); if (index == -1) { @@ -799,7 +799,7 @@ public class QuestionnaireValidator extends BaseValidator { } private boolean validateAnswerCode(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean theOpenChoice) { - Element v = answer.getNamedChild("valueCoding"); + Element v = answer.getNamedChild("valueCoding", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) checkCodingOption(errors, answer, stack, qSrc, qItem, theOpenChoice); @@ -826,7 +826,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean checkIntegerOption(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { boolean ok = true; - Element v = answer.getNamedChild("valueInteger"); + Element v = answer.getNamedChild("valueInteger", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) { List list = new ArrayList(); @@ -859,7 +859,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean checkDateOption(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { boolean ok = true; - Element v = answer.getNamedChild("valueDate"); + Element v = answer.getNamedChild("valueDate", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) { List list = new ArrayList(); @@ -892,7 +892,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean checkTimeOption(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { boolean ok = true; - Element v = answer.getNamedChild("valueTime"); + Element v = answer.getNamedChild("valueTime", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) { List list = new ArrayList(); @@ -925,7 +925,7 @@ public class QuestionnaireValidator extends BaseValidator { private boolean checkStringOption(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { boolean ok = true; - Element v = answer.getNamedChild("valueString"); + Element v = answer.getNamedChild("valueString", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) { List list = new ArrayList(); @@ -963,9 +963,9 @@ public class QuestionnaireValidator extends BaseValidator { private boolean checkCodingOption(List errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { boolean ok = true; - Element v = answer.getNamedChild("valueCoding"); - String system = v.getNamedChildValue("system"); - String code = v.getNamedChildValue("code"); + Element v = answer.getNamedChild("valueCoding", false); + String system = v.getNamedChildValue("system", false); + String code = v.getNamedChildValue("code", false); NodeStack ns = stack.push(v, -1, null, null); if (qItem.getAnswerOption().size() > 0) { List list = new ArrayList(); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/SearchParameterValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/SearchParameterValidator.java index 7d67bb852..bbe2a9f7d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/SearchParameterValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/SearchParameterValidator.java @@ -42,14 +42,14 @@ public class SearchParameterValidator extends BaseValidator { boolean ok = true; // String url = cs.getNamedChildValue("url"); - if (cs.hasChild("expression")) { + if (cs.hasChild("expression", false)) { List bases = new ArrayList<>(); for (Element b : cs.getChildrenByName("base")) { bases.add(b.primitiveValue()); } - ok = checkExpression(errors, stack.push(cs.getNamedChild("expression"), -1, null, null), cs.getNamedChildValue("expression"), bases) && ok; + ok = checkExpression(errors, stack.push(cs.getNamedChild("expression", false), -1, null, null), cs.getNamedChildValue("expression", false), bases) && ok; } - String master = cs.getNamedChildValue("derivedFrom"); + String master = cs.getNamedChildValue("derivedFrom", false); if (!Utilities.noString(master)) { SearchParameter sp = context.fetchResource(SearchParameter.class, master); if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp != null, I18nConstants.SEARCHPARAMETER_NOTFOUND, master)) { @@ -58,15 +58,15 @@ public class SearchParameterValidator extends BaseValidator { for (Element b : bl) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp.hasBase(b.primitiveValue()) || sp.hasBase("Resource"), I18nConstants.SEARCHPARAMETER_BASE_WRONG, master, b.primitiveValue()) && ok; } - ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), !cs.hasChild("type") || sp.getType().toCode().equals(cs.getNamedChildValue("type")), I18nConstants.SEARCHPARAMETER_TYPE_WRONG, master, sp.getType().toCode(), cs.getNamedChildValue("type")) && ok; - if (sp.hasExpression() && cs.hasChild("expression") && !sp.getExpression().equals(cs.getNamedChildValue("expression"))) { + ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), !cs.hasChild("type", false) || sp.getType().toCode().equals(cs.getNamedChildValue("type", false)), I18nConstants.SEARCHPARAMETER_TYPE_WRONG, master, sp.getType().toCode(), cs.getNamedChildValue("type", false)) && ok; + if (sp.hasExpression() && cs.hasChild("expression", false) && !sp.getExpression().equals(cs.getNamedChildValue("expression", false))) { List bases = new ArrayList<>(); for (Element b : cs.getChildren("base")) { bases.add(b.primitiveValue()); } - String expThis = canonicalise(cs.getNamedChildValue("expression"), bases); + String expThis = canonicalise(cs.getNamedChildValue("expression", false), bases); String expOther = canonicalise(sp.getExpression(), bases); - warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), expThis.equals(expOther), I18nConstants.SEARCHPARAMETER_EXP_WRONG, master, sp.getExpression(), cs.getNamedChildValue("expression")); + warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), expThis.equals(expOther), I18nConstants.SEARCHPARAMETER_EXP_WRONG, master, sp.getExpression(), cs.getNamedChildValue("expression", false)); } // todo: check compositions diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index 5c34b8b50..0921418b9 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -76,7 +76,7 @@ public class StructureDefinitionValidator extends BaseValidator { StructureDefinition sd = null; String typeName = null; try { - String url = src.getNamedChildValue("url"); + String url = src.getNamedChildValue("url", false); sd = loadAsSD(src); ok = checkExtensionContext(errors, src, stack) && ok; @@ -131,22 +131,22 @@ public class StructureDefinitionValidator extends BaseValidator { List differentials = src.getChildrenByName("differential"); List snapshots = src.getChildrenByName("snapshot"); - boolean logical = "logical".equals(src.getNamedChildValue("kind")); - boolean constraint = "constraint".equals(src.getNamedChildValue("derivation")); + boolean logical = "logical".equals(src.getNamedChildValue("kind", false)); + boolean constraint = "constraint".equals(src.getNamedChildValue("derivation", false)); for (Element differential : differentials) { - ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type"), src.getNamedChildValue("url"), src.getNamedChildValue("type"), base) && ok; + ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; } for (Element snapshotE : snapshots) { - ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type"), src.getNamedChildValue("url"), src.getNamedChildValue("type"), base) && ok; + ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; } // obligation profile support if (src.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { Element ext = src.getExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG); - Element value = ext.getNamedChild("value"); + Element value = ext.getNamedChild("value", false); if (value != null && "true".equals(value.primitiveValue())) { - if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), "constraint".equals(src.getNamedChildValue("derivation")), I18nConstants.SD_OBGLIGATION_PROFILE_DERIVATION)) { - if (warning(errors, "2023-05-27", IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.SD_OBGLIGATION_PROFILE_UKNOWN, src.getNamedChildValue("baseDefinition"))) { + if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), "constraint".equals(src.getNamedChildValue("derivation", false)), I18nConstants.SD_OBGLIGATION_PROFILE_DERIVATION)) { + if (warning(errors, "2023-05-27", IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.SD_OBGLIGATION_PROFILE_UKNOWN, src.getNamedChildValue("baseDefinition", false))) { for (Element differential : differentials) { ok = validateObligationProfile(errors, differential, stack.push(differential, -1, null, null), base) && ok; } @@ -160,7 +160,7 @@ public class StructureDefinitionValidator extends BaseValidator { List extensions = src.getChildren("extension"); int c = 0; for (Element extension : extensions) { - if (ToolingExtensions.EXT_OBLIGATION_INHERITS.equals(extension.getNamedChildValue("url"))) { + if (ToolingExtensions.EXT_OBLIGATION_INHERITS.equals(extension.getNamedChildValue("url", false))) { ok = validateInheritsObligationProfile(errors, extension, stack.push(extension, c, null, null), src) && ok; } c++; @@ -174,9 +174,9 @@ public class StructureDefinitionValidator extends BaseValidator { } // if this is defining an extension, make sure that the extension fixed value matches the URL - String type = src.getNamedChildValue("type"); + String type = src.getNamedChildValue("type", false); if ("Extension".equals(type)) { - String baseD = src.getNamedChildValue("baseDefinition"); + String baseD = src.getNamedChildValue("baseDefinition", false); if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(baseD) && url != null) { String fixedUrl = getFixedValue(src); if (rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), fixedUrl != null, I18nConstants.SD_EXTENSION_URL_MISSING, url)) { @@ -195,12 +195,12 @@ public class StructureDefinitionValidator extends BaseValidator { private String getFixedValue(Element src) { - Element diff = src.getNamedChild("differential"); + Element diff = src.getNamedChild("differential", false); if (diff != null) { for (Element ed : diff.getChildrenByName("element")) { - String path = ed.getNamedChildValue("path"); + String path = ed.getNamedChildValue("path", false); if ("Extension.url".equals(path)) { - return ed.getNamedChildValue("fixed"); + return ed.getNamedChildValue("fixed", false); } } } @@ -208,7 +208,7 @@ public class StructureDefinitionValidator extends BaseValidator { } private boolean validateInheritsObligationProfile(List errors, Element extension, NodeStack stack, Element src) { - String tgt = extension.getNamedChildValue("value"); + String tgt = extension.getNamedChildValue("value", false); if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), tgt != null, I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NO_TARGET)) { StructureDefinition sd = context.fetchResource(StructureDefinition.class, tgt); @@ -216,7 +216,7 @@ public class StructureDefinitionValidator extends BaseValidator { I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_TARGET_NOT_FOUND, tgt)) { if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), ToolingExtensions.readBoolExtension(sd, ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG), I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_TYPE, tgt)) { - String base = src.getNamedChildValue("baseDefinition"); + String base = src.getNamedChildValue("baseDefinition", false); if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), base != null && base.equals(sd.getBaseDefinition()), I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_BASE, tgt, sd.getBaseDefinition(), base)) { return true; @@ -241,7 +241,7 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean validateObligationProfileElement(List errors, Element element, NodeStack push, StructureDefinition base) { // rules: it must exist in the base snapshot // it must only add must-support, obligations and extra bindings - String id = element.getNamedChildValue("id"); + String id = element.getNamedChildValue("id", false); ElementDefinition bd = base.getSnapshot().getElementById(id); if (rule(errors, "2023-05-27", IssueType.INVALID, push.getLiteralPath(), bd != null, I18nConstants.SD_OBGLIGATION_PROFILE_UNMATCHED, id, base.getVersionedUrl())) { boolean ok = true; @@ -256,7 +256,7 @@ public class StructureDefinitionValidator extends BaseValidator { } NodeStack stack = push.push(child, c, null, null); if (child.getName().equals("extension")) { - String url = child.getNamedChildValue("url"); + String url = child.getNamedChildValue("url", false); if (Utilities.existsInList(url, ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { // this is ok, and it doesn't matter what's in the obligation } else { @@ -304,11 +304,11 @@ public class StructureDefinitionValidator extends BaseValidator { } NodeStack stack = nstack.push(child, c, null, null); if (child.getName().equals("extension")) { - String url = child.getNamedChildValue("url"); + String url = child.getNamedChildValue("url", false); if ("http://hl7.org/fhir/tools/StructureDefinition/additional-binding".equals(url) && !VersionUtilities.isR5Plus(context.getVersion())) { Element purpose = child.getExtension("purpose"); if (purpose != null) { // should be an error elsewhere - String code = purpose.getNamedChildValue("value"); + String code = purpose.getNamedChildValue("value", false); ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"), I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok; @@ -319,7 +319,7 @@ public class StructureDefinitionValidator extends BaseValidator { I18nConstants.SD_OBGLIGATION_PROFILE_ILLEGAL, id, child.getName()+"#"+url); } } else if (child.getName().equals("additional") && VersionUtilities.isR5Plus(context.getVersion())) { - String code = child.getNamedChildValue("purpose"); + String code = child.getNamedChildValue("purpose", false); ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"), I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok; } else if (child.getName().equals("strength")) { @@ -339,7 +339,7 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean checkExtensionContext(List errors, Element src, NodeStack stack) { boolean ok = true; - String type = src.getNamedChildValue("type"); + String type = src.getNamedChildValue("type", false); List eclist = src.getChildren("context"); List cilist = src.getChildren("contextInvariant"); int i = 0; @@ -349,14 +349,14 @@ public class StructureDefinitionValidator extends BaseValidator { String ct = null; String cv = null; if (VersionUtilities.isR4Plus(context.getVersion())) { - ct = ec.getNamedChildValue("type"); - cv = ec.getNamedChildValue("expression"); + ct = ec.getNamedChildValue("type", false); + cv = ec.getNamedChildValue("expression", false); } else { - ct = src.getNamedChildValue("contextType"); /// todo - this doesn't have the right value + ct = src.getNamedChildValue("contextType", false); /// todo - this doesn't have the right value cv = ec.primitiveValue(); } if ("element".equals(ct) && "Element".equals(cv)) { - warning(errors, "2023-04-23", IssueType.BUSINESSRULE, n.getLiteralPath(), false, I18nConstants.SD_CONTEXT_SHOULD_NOT_BE_ELEMENT, cv, src.getNamedChildValue("id")); + warning(errors, "2023-04-23", IssueType.BUSINESSRULE, n.getLiteralPath(), false, I18nConstants.SD_CONTEXT_SHOULD_NOT_BE_ELEMENT, cv, src.getNamedChildValue("id", false)); } } else { ok = rule(errors, "2023-04-23", IssueType.INVALID, n.getLiteralPath(), false, I18nConstants.SD_NO_CONTEXT_WHEN_NOT_EXTENSION, type) && ok; @@ -389,12 +389,12 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean validateElementDefinition(List errors, List elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base) { boolean ok = true; boolean typeMustSupport = false; - String path = element.getNamedChildValue("path"); + String path = element.getNamedChildValue("path", false); ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), typeName == null || path == null || path.equals(typeName) || path.startsWith(typeName+"."), I18nConstants.SD_PATH_TYPE_MISMATCH, typeName, path) && ok; if (!snapshot) { - ok = rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing"), I18nConstants.SD_NO_SLICING_ON_ROOT, path) && ok; + ok = rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing", false), I18nConstants.SD_NO_SLICING_ON_ROOT, path) && ok; } - ok = rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), snapshot || !constraint || !element.hasChild("meaningWhenMissing") || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path) && ok; + ok = rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), snapshot || !constraint || !element.hasChild("meaningWhenMissing", false) || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path) && ok; List types = element.getChildrenByName("type"); Set typeCodes = new HashSet<>(); @@ -415,7 +415,7 @@ public class StructureDefinitionValidator extends BaseValidator { tc = tcv.primitiveValue(); } } - if (Utilities.noString(tc) && type.hasChild("code")) { + if (Utilities.noString(tc) && type.hasChild("code", false)) { if (VersionUtilities.isR4Plus(context.getVersion())) { ok = rule(errors, "2023-03-16", IssueType.INVALID, stack.getLiteralPath(), false, I18nConstants.SD_NO_TYPE_CODE_ON_CODE, path, sd.getId()) && ok; } @@ -449,28 +449,28 @@ public class StructureDefinitionValidator extends BaseValidator { hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, path); } } - if (element.hasChild("binding")) { + if (element.hasChild("binding", false)) { if (!typeCodes.isEmpty()) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok; } - Element binding = element.getNamedChild("binding"); + Element binding = element.getNamedChild("binding", false); ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok; } else { // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back // String bt = boundType(typeCodes); -// hint(errors, UNKNOWN_DATE_TIME, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt); +// hint(errors, UNKNOWN_DATE_TIME, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path", false), bt); } if (!typeCodes.isEmpty()) { - if (element.hasChild("maxLength")) { + if (element.hasChild("maxLength", false)) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxLength", typeCodes) && ok; } if (element.hasExtension(ToolingExtensions.EXT_MIN_LENGTH)) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinLength Extension", typeCodes) && ok; } - if (element.hasChild("minValue")) { + if (element.hasChild("minValue", false)) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinValue", typeCodes) && ok; } - if (element.hasChild("maxValue")) { + if (element.hasChild("maxValue", false)) { ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxValue", typeCodes) && ok; } if (element.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) { @@ -482,15 +482,15 @@ public class StructureDefinitionValidator extends BaseValidator { } // in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) { - if (rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) { + if (rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference", false), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) { // if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint boolean repeating = !Utilities.existsInList(element.getChildValue("max"), "0", "1"); - Element v = element.getNamedChild("defaultValue"); + Element v = element.getNamedChild("defaultValue", false); if (v != null) { ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes) && ok; } - v = element.getNamedChild("fixed"); + v = element.getNamedChild("fixed", false); if (v != null) { ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes) && ok; hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed"); @@ -500,7 +500,7 @@ public class StructureDefinitionValidator extends BaseValidator { warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), false, I18nConstants.SD_VALUE_COMPLEX_FIXED, v.fhirType()); } } - v = element.getNamedChild("pattern"); + v = element.getNamedChild("pattern", false); if (v != null) { ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes) && ok; hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern"); @@ -516,7 +516,7 @@ public class StructureDefinitionValidator extends BaseValidator { List constraints = element.getChildrenByName("constraint"); int cc = 0; for (Element invariant : constraints) { - ok = validateElementDefinitionInvariant(errors, invariant, stack.push(invariant, cc, null, null), invariantMap, elements, element, element.getNamedChildValue("path"), rootPath, profileUrl, profileType, snapshot, base) && ok; + ok = validateElementDefinitionInvariant(errors, invariant, stack.push(invariant, cc, null, null), invariantMap, elements, element, element.getNamedChildValue("path", false), rootPath, profileUrl, profileType, snapshot, base) && ok; cc++; } return ok; @@ -525,9 +525,9 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean validateElementDefinitionInvariant(List errors, Element invariant, NodeStack stack, Map invariantMap, List elements, Element element, String path, String rootPath, String profileUrl, String profileType, boolean snapshot, StructureDefinition base) { boolean ok = true; - String key = invariant.getNamedChildValue("key"); - String expression = invariant.getNamedChildValue("expression"); - String source = invariant.getNamedChildValue("source"); + String key = invariant.getNamedChildValue("key", false); + String expression = invariant.getNamedChildValue("expression", false); + String source = invariant.getNamedChildValue("source", false); if (warning(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(key), I18nConstants.ED_INVARIANT_NO_KEY)) { if (hint(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(expression) || VersionUtilities.isR5Plus(context.getVersion()), I18nConstants.ED_INVARIANT_NO_EXPRESSION, key)) { // not for R5 - there's an invariant if (snapshot) {// we just don't have enough information to figure out the context in a differential @@ -554,7 +554,7 @@ public class StructureDefinitionValidator extends BaseValidator { } if (types.size() == 0) { // we got to the root before finding anything typed - types.add(elements.get(0).getNamedChildValue("path")); + types.add(elements.get(0).getNamedChildValue("path", false)); } List warnings = new ArrayList<>(); ValidationContext vc = new ValidationContext(invariant); @@ -619,7 +619,7 @@ public class StructureDefinitionValidator extends BaseValidator { private Object listContexts(Element sd) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (Element e : sd.getChildren("context")) { - b.append(e.getNamedChildValue("type")+"="+e.getNamedChildValue("expression")); + b.append(e.getNamedChildValue("type", false)+"="+e.getNamedChildValue("expression", false)); } return b.toString(); } @@ -627,16 +627,16 @@ public class StructureDefinitionValidator extends BaseValidator { private List listTypeContexts(Element sd) { List types = new ArrayList<>(); for (Element e : sd.getChildren("context")) { - switch (e.getNamedChildValue("type")) { + switch (e.getNamedChildValue("type", false)) { case "fhirpath" : break; case "element" : - types.add(e.getNamedChildValue("expression")); + types.add(e.getNamedChildValue("expression", false)); break; case "extension" : // this isn't defined? - types.add(e.getNamedChildValue("Extension")); - types.add(e.getNamedChildValue("Extension.value")); + types.add(e.getNamedChildValue("Extension", false)); + types.add(e.getNamedChildValue("Extension.value", false)); break; default: } @@ -656,16 +656,16 @@ public class StructureDefinitionValidator extends BaseValidator { } private String tail(Element te, Element newte) { - String p = te.getNamedChildValue("path"); - String pn = newte.getNamedChildValue("path"); + String p = te.getNamedChildValue("path", false); + String pn = newte.getNamedChildValue("path", false); return p.substring(pn.length()+1); } private Element getParent(List elements, Element te) { int i = elements.indexOf(te) - 1; - String path = te.getNamedChildValue("path"); + String path = te.getNamedChildValue("path", false); while (i >= 0) { - String p = elements.get(i).getNamedChildValue("path"); + String p = elements.get(i).getNamedChildValue("path", false); if (path.startsWith(p+".")) { return elements.get(i); } @@ -676,8 +676,8 @@ public class StructureDefinitionValidator extends BaseValidator { private List getTypesForElement(List elements, Element element, String profileType) { List types = new ArrayList<>(); - if (element.hasChild("path") && !element.getNamedChildValue("path").contains(".")) { - String t = element.getNamedChildValue("path"); + if (element.hasChild("path", false) && !element.getNamedChildValue("path", false).contains(".")) { + String t = element.getNamedChildValue("path", false); if (profileType.equals(t)) { types.add(profileType); } else if (profileType.endsWith("/"+t)) { @@ -687,16 +687,16 @@ public class StructureDefinitionValidator extends BaseValidator { } } else { for (Element tr : element.getChildrenByName("type")) { - String t = tr.getNamedChildValue("code"); + String t = tr.getNamedChildValue("code", false); if (t.startsWith("http://hl7.org/fhirpath")) { t = tr.getExtensionValue("http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type").primitiveValue(); } if (t != null) { if (isAbstractType(t) && hasChildren(element, elements) ) { if (!Utilities.isAbsoluteUrl(profileType)) { - types.add(element.getNamedChildValue("path")); + types.add(element.getNamedChildValue("path", false)); } else { - types.add(profileType+"#"+element.getNamedChildValue("path")); + types.add(profileType+"#"+element.getNamedChildValue("path", false)); } } else { types.add(t); @@ -709,9 +709,9 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean hasChildren(Element element, List elements) { int i = elements.indexOf(element); - String path = element.getNamedChildValue("path")+"."; + String path = element.getNamedChildValue("path", false)+"."; while (i < elements.size()) { - String p = elements.get(i).getNamedChildValue("path")+"."; + String p = elements.get(i).getNamedChildValue("path", false)+"."; if (p.startsWith(path)) { return true; } @@ -727,7 +727,7 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean meaningWhenMissingAllowed(Element element) { // allowed to use meaningWhenMissing on the root of an element to say what it means when the extension // is not present. - String path = element.getNamedChildValue("path"); + String path = element.getNamedChildValue("path", false); return path != null && ("Extension".equals(path) || (path.endsWith(".extension"))); } @@ -866,9 +866,9 @@ public class StructureDefinitionValidator extends BaseValidator { hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), bindables.size() <= 1, I18nConstants.SD_ED_BIND_MULTIPLE_TYPES, path, typeCodes.toString()); } - if (binding.hasChild("valueSet")) { - Element valueSet = binding.getNamedChild("valueSet"); - String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("reference"); + if (binding.hasChild("valueSet", false)) { + Element valueSet = binding.getNamedChild("valueSet", false); + String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("reference", false); if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) { Resource vs = context.fetchResource(Resource.class, ref); @@ -901,7 +901,7 @@ public class StructureDefinitionValidator extends BaseValidator { private boolean validateElementType(List errors, Element type, NodeStack stack, StructureDefinition sd, String path, boolean logical) { boolean ok = true; - String code = type.getNamedChildValue("code"); + String code = type.getNamedChildValue("code", false); if (code == null && path != null) { code = getTypeCodeFromSD(sd, path); } else { @@ -1118,8 +1118,8 @@ public class StructureDefinitionValidator extends BaseValidator { private String getExtensionValue(Element element, String url) { List extensions = element.getChildrenByName("extension"); for (Element extension : extensions) { - if (url.equals(extension.getNamedChildValue("url"))) { - return extension.getNamedChildValue("value"); + if (url.equals(extension.getNamedChildValue("url", false))) { + return extension.getNamedChildValue("value", false); } } return null; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java index 4dc106aef..261b090bb 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java @@ -355,7 +355,7 @@ public class StructureMapValidator extends BaseValidator { private boolean hasInputTypes(Element group) { List inputs = group.getChildrenByName("input"); for (Element input : inputs) { - if (!input.hasChild("type")) { + if (!input.hasChild("type", false)) { return false; } } @@ -385,7 +385,7 @@ public class StructureMapValidator extends BaseValidator { grpNames.add(name); } - Element extend = group.getNamedChild("extends"); + Element extend = group.getNamedChild("extends", false); if (extend != null) { ResolvedGroup grp = resolveGroup(extend.primitiveValue(), src); if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, extend.primitiveValue())) { @@ -774,14 +774,14 @@ public class StructureMapValidator extends BaseValidator { break; case "cc" : ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 2 || params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; - ok = checkParamExistsOrPrimitive(errors, params.size() > 0 ? params.get(0).getNamedChild("value") : null, "cc", "system", target, variables, stack, ok, true); - ok = checkParamExistsOrPrimitive(errors, params.size() > 1 ? params.get(1).getNamedChild("value") : null, "cc", "code", target, variables, stack, ok, true); - ok = checkParamExistsOrPrimitive(errors, params.size() > 2 ? params.get(2).getNamedChild("value") : null, "cc", "display", target, variables, stack, ok, false); + ok = checkParamExistsOrPrimitive(errors, params.size() > 0 ? params.get(0).getNamedChild("value", false) : null, "cc", "system", target, variables, stack, ok, true); + ok = checkParamExistsOrPrimitive(errors, params.size() > 1 ? params.get(1).getNamedChild("value", false) : null, "cc", "code", target, variables, stack, ok, true); + ok = checkParamExistsOrPrimitive(errors, params.size() > 2 ? params.get(2).getNamedChild("value", false) : null, "cc", "display", target, variables, stack, ok, false); break; case "append" : ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() > 0, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; for (int i = 0; i < params.size(); i++) { - ok = checkParamExistsOrPrimitive(errors, params.get(1).getNamedChild("value"), "cc", "parameter "+i, target, variables, stack, ok, false); + ok = checkParamExistsOrPrimitive(errors, params.get(1).getNamedChild("value", false), "cc", "parameter "+i, target, variables, stack, ok, false); } break; case "uuid" : @@ -789,9 +789,9 @@ public class StructureMapValidator extends BaseValidator { break; case "translate": ok = rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; - Element srcE = params.size() > 0 ? params.get(0).getNamedChild("value") : null; - Element mapE = params.size() > 1? params.get(1).getNamedChild("value") : null; - Element modeE = params.size() > 2 ? params.get(2).getNamedChild("value") : null; + Element srcE = params.size() > 0 ? params.get(0).getNamedChild("value", false) : null; + Element mapE = params.size() > 1? params.get(1).getNamedChild("value", false) : null; + Element modeE = params.size() > 2 ? params.get(2).getNamedChild("value", false) : null; VariableDefn sv = null; // srcE - if it's an id, the variable must exist if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), srcE != null, I18nConstants.SM_TARGET_TRANSFORM_TRANSLATE_NO_PARAM, "source")) { @@ -1205,7 +1205,7 @@ public class StructureMapValidator extends BaseValidator { List structures = map.getChildrenByName("structure"); for (Element structure : structures) { String alias = structure.getChildValue("alias"); - if ((alias != null && alias.equals(type)) && (mode == null || mode.equals(structure.getNamedChildValue("mode")))) { + if ((alias != null && alias.equals(type)) && (mode == null || mode.equals(structure.getNamedChildValue("mode", false)))) { return structure.getChildValue("url"); } } @@ -1301,7 +1301,7 @@ public class StructureMapValidator extends BaseValidator { private VariableDefn getParameter(List errors, Element param, NodeStack pstack, VariableSet variables, StructureMapInputMode mode) { if (VersionUtilities.isR5Plus(context.getVersion())) { - Element v = param.getNamedChild("value"); + Element v = param.getNamedChild("value", false); if (v.fhirType().equals("id")) { return variables.getVariable(v.primitiveValue(), mode == StructureMapInputMode.SOURCE); } else { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index a131a99c3..5c572c82e 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -62,7 +62,7 @@ public class ValueSetValidator extends BaseValidator { List composes = vs.getChildrenByName("compose"); int cc = 0; for (Element compose : composes) { - ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok; + ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url", false), "retired".equals(vs.getNamedChildValue("url", false))) & ok; cc++; } } @@ -76,22 +76,22 @@ public class ValueSetValidator extends BaseValidator { if (parent.isForPublication()) { if (isHL7(vs)) { boolean ok = true; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "url") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "version") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "title") && ok; - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name"), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING_HL7, "name"); - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "status") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "experimental") && ok; - ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "description") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "url") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "version") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "title") && ok; + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name", false), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING_HL7, "name"); + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "status") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "experimental") && ok; + ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "description") && ok; return ok; } else { - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url"), I18nConstants.VALUESET_SHAREABLE_MISSING, "url"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version"), I18nConstants.VALUESET_SHAREABLE_MISSING, "version"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title"), I18nConstants.VALUESET_SHAREABLE_MISSING, "title"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name"), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING, "name"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status"), I18nConstants.VALUESET_SHAREABLE_MISSING, "status"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental"), I18nConstants.VALUESET_SHAREABLE_MISSING, "experimental"); - warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description"), I18nConstants.VALUESET_SHAREABLE_MISSING, "description"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "url"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "version"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "title"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name", false), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING, "name"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "status"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "experimental"); + warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "description"); } } return true; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java index ea945495f..231decf1f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/EnableWhenEvaluator.java @@ -395,7 +395,7 @@ public class EnableWhenEvaluator { } private boolean hasLinkId(Element item, String linkId) { - Element linkIdChild = item.getNamedChild(LINKID_ELEMENT); + Element linkIdChild = item.getNamedChild(LINKID_ELEMENT, false); if (linkIdChild != null && linkIdChild.getValue().equals(linkId)) { return true; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java index da5d1c817..a4f366331 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java @@ -122,7 +122,7 @@ public class IPAValidator { List entries = bundle.getChildren("entry"); int i = 0; for (Element entry : entries) { - Element resource = entry.getNamedChild("resource"); + Element resource = entry.getNamedChild("resource", false); if (resource != null && resource.fhirType().equals("Patient")) { validator.validate(this, vn.getIssues(), "Bundle.entry["+i+"].resource", resource, "http://hl7.org/fhir/uv/ipa/StructureDefinition/ipa-patient"); list.add(resource); @@ -145,8 +145,8 @@ public class IPAValidator { // we check that there's a self link Element sl = null; for (Element e : bundle.getChildren("link")) { - if ("self".equals(e.getNamedChildValue("relation"))) { - sl = e.getNamedChild("url"); + if ("self".equals(e.getNamedChildValue("relation", false))) { + sl = e.getNamedChild("url", false); } } if (sl == null) { From 220210bca35280cfd6be595f92f4c9dc820e6f31 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 15 Nov 2023 18:06:55 +1100 Subject: [PATCH 3/3] fix failing test --- .../src/main/resources/Messages_es.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages_es.properties b/org.hl7.fhir.utilities/src/main/resources/Messages_es.properties index 210aa9aaf..b5f32cff0 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages_es.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages_es.properties @@ -837,3 +837,6 @@ SD_ED_TYPE_PROFILE_WRONG_TYPE_other = VALUESET_SUPPLEMENT_MISSING_one = VALUESET_SUPPLEMENT_MISSING_many = VALUESET_SUPPLEMENT_MISSING_other = +BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_one = +BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_many = +BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_other =