Refactored ElementInfo

This commit is contained in:
markiantorno 2020-02-21 15:34:55 -05:00
parent 4df9e568e6
commit ae30afdf53
2 changed files with 181 additions and 52 deletions

View File

@ -4805,7 +4805,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} else if (ei.definition.getType().size() == 1 && "*".equals(ei.definition.getType().get(0).getWorkingCode())) { } else if (ei.definition.getType().size() == 1 && "*".equals(ei.definition.getType().get(0).getWorkingCode())) {
String prefix = tail(ei.definition.getPath()); String prefix = tail(ei.definition.getPath());
assert prefix.endsWith("[x]"); assert prefix.endsWith("[x]");
type = ei.name.substring(prefix.length() - 3); type = ei.getName().substring(prefix.length() - 3);
if (isPrimitiveType(type)) if (isPrimitiveType(type))
type = Utilities.uncapitalize(type); type = Utilities.uncapitalize(type);
if (ei.definition.getType().get(0).hasProfile()) { if (ei.definition.getType().get(0).hasProfile()) {
@ -4819,11 +4819,11 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
assert typesAreAllReference(ei.definition.getType()) || ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR) || prefix.endsWith("[x]") : prefix; assert typesAreAllReference(ei.definition.getType()) || ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR) || prefix.endsWith("[x]") : prefix;
if (ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR)) if (ei.definition.hasRepresentation(PropertyRepresentation.TYPEATTR))
type = ei.element.getType(); type = ei.getElement().getType();
else { else {
prefix = prefix.substring(0, prefix.length() - 3); prefix = prefix.substring(0, prefix.length() - 3);
for (TypeRefComponent t : ei.definition.getType()) for (TypeRefComponent t : ei.definition.getType())
if ((prefix + Utilities.capitalize(t.getWorkingCode())).equals(ei.name)) { if ((prefix + Utilities.capitalize(t.getWorkingCode())).equals(ei.getName())) {
type = t.getWorkingCode(); type = t.getWorkingCode();
// Excluding reference is a kludge to get around versioning issues // Excluding reference is a kludge to get around versioning issues
if (t.hasProfile() && !type.equals("Reference")) if (t.hasProfile() && !type.equals("Reference"))
@ -4836,7 +4836,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
type = "Reference"; type = "Reference";
else else
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), false, rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), false,
"The type of element " + ei.name + " is not known, which is illegal. Valid types at this point are " + describeTypes(ei.definition.getType())); "The type of element " + ei.getName() + " is not known, which is illegal. Valid types at this point are " + describeTypes(ei.definition.getType()));
} }
} else if (ei.definition.getContentReference() != null) { } else if (ei.definition.getContentReference() != null) {
typeDefn = resolveNameReference(profile.getSnapshot(), ei.definition.getContentReference()); typeDefn = resolveNameReference(profile.getSnapshot(), ei.definition.getContentReference());
@ -4856,55 +4856,55 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
type = null; type = null;
} }
} }
NodeStack localStack = stack.push(ei.element, ei.count, ei.definition, type == null ? typeDefn : resolveType(type, ei.definition.getType())); NodeStack localStack = stack.push(ei.getElement(), ei.count, ei.definition, type == null ? typeDefn : resolveType(type, ei.definition.getType()));
if (debug) { if (debug) {
System.out.println(" "+localStack.getLiteralPath()); System.out.println(" "+localStack.getLiteralPath());
} }
String localStackLiterapPath = localStack.getLiteralPath(); String localStackLiterapPath = localStack.getLiteralPath();
String eiPath = ei.path; String eiPath = ei.getPath();
assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.path + " - localStack.getLiteralPath: " + localStackLiterapPath; assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.getPath() + " - localStack.getLiteralPath: " + localStackLiterapPath;
boolean thisIsCodeableConcept = false; boolean thisIsCodeableConcept = false;
String thisExtension = null; String thisExtension = null;
boolean checkDisplay = true; boolean checkDisplay = true;
checkInvariants(hostContext, errors, profile, ei.definition, resource, ei.element, localStack, true); checkInvariants(hostContext, errors, profile, ei.definition, resource, ei.getElement(), localStack, true);
ei.element.markValidation(profile, ei.definition); ei.getElement().markValidation(profile, ei.definition);
boolean elementValidated = false; boolean elementValidated = false;
if (type != null) { if (type != null) {
if (isPrimitiveType(type)) { if (isPrimitiveType(type)) {
checkPrimitive(hostContext, errors, ei.path, type, ei.definition, ei.element, profile, stack); checkPrimitive(hostContext, errors, ei.getPath(), type, ei.definition, ei.getElement(), profile, stack);
} else { } else {
if (ei.definition.hasFixed()) { if (ei.definition.hasFixed()) {
checkFixedValue(errors,ei.path, ei.element, ei.definition.getFixed(), profile.getUrl(), ei.definition.getSliceName(), null); checkFixedValue(errors,ei.getPath(), ei.getElement(), ei.definition.getFixed(), profile.getUrl(), ei.definition.getSliceName(), null);
} }
if (ei.definition.hasPattern()) { if (ei.definition.hasPattern()) {
checkFixedValue(errors,ei.path, ei.element, ei.definition.getPattern(), profile.getUrl(), ei.definition.getSliceName(), null, true); checkFixedValue(errors,ei.getPath(), ei.getElement(), ei.definition.getPattern(), profile.getUrl(), ei.definition.getSliceName(), null, true);
} }
} }
if (type.equals("Identifier")) { if (type.equals("Identifier")) {
checkIdentifier(errors, ei.path, ei.element, ei.definition); checkIdentifier(errors, ei.getPath(), ei.getElement(), ei.definition);
} else if (type.equals("Coding")) { } else if (type.equals("Coding")) {
checkCoding(errors, ei.path, ei.element, profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack); checkCoding(errors, ei.getPath(), ei.getElement(), profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack);
} else if (type.equals("CodeableConcept")) { } else if (type.equals("CodeableConcept")) {
checkDisplay = checkCodeableConcept(errors, ei.path, ei.element, profile, ei.definition, stack); checkDisplay = checkCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, ei.definition, stack);
thisIsCodeableConcept = true; thisIsCodeableConcept = true;
} else if (type.equals("Reference")) { } else if (type.equals("Reference")) {
checkReference(hostContext, errors, ei.path, ei.element, profile, ei.definition, actualType, localStack); checkReference(hostContext, errors, ei.getPath(), ei.getElement(), profile, ei.definition, actualType, localStack);
// 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 // 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")) { } else if (type.equals("Extension")) {
Element eurl = ei.element.getNamedChild("url"); Element eurl = ei.getElement().getNamedChild("url");
if (rule(errors, IssueType.INVALID, ei.path, eurl != null, "Extension.url is required")) { if (rule(errors, IssueType.INVALID, ei.getPath(), eurl != null, "Extension.url is required")) {
String url = eurl.primitiveValue(); String url = eurl.primitiveValue();
thisExtension = url; thisExtension = url;
if (rule(errors, IssueType.INVALID, ei.path, !Utilities.noString(url), "Extension.url is required")) { if (rule(errors, IssueType.INVALID, ei.getPath(), !Utilities.noString(url), "Extension.url is required")) {
if (rule(errors, IssueType.INVALID, ei.path, (extensionUrl != null) || Utilities.isAbsoluteUrl(url), "Extension.url must be an absolute URL")) { if (rule(errors, IssueType.INVALID, ei.getPath(), (extensionUrl != null) || Utilities.isAbsoluteUrl(url), "Extension.url must be an absolute URL")) {
checkExtension(hostContext, errors, ei.path, resource, element, ei.element, ei.definition, profile, localStack, stack, extensionUrl); checkExtension(hostContext, errors, ei.getPath(), resource, element, ei.getElement(), ei.definition, profile, localStack, stack, extensionUrl);
} }
} }
} }
} else if (type.equals("Resource")) { } else if (type.equals("Resource")) {
validateContains(hostContext, errors, ei.path, ei.definition, definition, resource, ei.element, localStack, idStatusForEntry(element, ei)); // if validateContains(hostContext, errors, ei.getPath(), ei.definition, definition, resource, ei.getElement(), localStack, idStatusForEntry(element, ei)); // if
elementValidated = true; elementValidated = true;
// (str.matches(".*([.,/])work\\1$")) // (str.matches(".*([.,/])work\\1$"))
} else if (Utilities.isAbsoluteUrl(type)) { } else if (Utilities.isAbsoluteUrl(type)) {
@ -4912,16 +4912,16 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (defn != null && hasMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep())) { if (defn != null && hasMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep())) {
List<String> txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep()); List<String> txtype = getMapping("http://hl7.org/fhir/terminology-pattern", defn, defn.getSnapshot().getElementFirstRep());
if (txtype.contains("CodeableConcept")) { if (txtype.contains("CodeableConcept")) {
checkTerminologyCodeableConcept(errors, ei.path, ei.element, profile, ei.definition, stack, defn); checkTerminologyCodeableConcept(errors, ei.getPath(), ei.getElement(), profile, ei.definition, stack, defn);
thisIsCodeableConcept = true; thisIsCodeableConcept = true;
} else if (txtype.contains("Coding")) { } else if (txtype.contains("Coding")) {
checkTerminologyCoding(errors, ei.path, ei.element, profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack, defn); checkTerminologyCoding(errors, ei.getPath(), ei.getElement(), profile, ei.definition, inCodeableConcept, checkDisplayInContext, stack, defn);
} }
} }
} }
} else { } else {
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), ei.definition != null, "Unrecognised Content " + ei.name)) if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), stack.getLiteralPath(), ei.definition != null, "Unrecognised Content " + ei.getName()))
validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.element, type, localStack, false, true, null); validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.getElement(), type, localStack, false, true, null);
} }
StructureDefinition p = null; StructureDefinition p = null;
String tail = null; String tail = null;
@ -4936,7 +4936,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
// checkInvariants(hostContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element); // checkInvariants(hostContext, errors, ei.path, profile, ei.definition, null, null, resource, ei.element);
//} //}
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown type " + type); rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, "Unknown type " + type);
} }
} else if (profiles.size()==1) { } else if (profiles.size()==1) {
String url = profiles.get(0); String url = profiles.get(0);
@ -4945,7 +4945,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
url = url.substring(0, url.indexOf("#")); url = url.substring(0, url.indexOf("#"));
} }
p = this.context.fetchResource(StructureDefinition.class, url); p = this.context.fetchResource(StructureDefinition.class, url);
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown profile " + profiles.get(0)); rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, "Unknown profile " + profiles.get(0));
} else { } else {
elementValidated = true; elementValidated = true;
HashMap<String, List<ValidationMessage>> goodProfiles = new HashMap<String, List<ValidationMessage>>(); HashMap<String, List<ValidationMessage>> goodProfiles = new HashMap<String, List<ValidationMessage>>();
@ -4958,9 +4958,9 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
url = url.substring(0, url.indexOf("#")); url = url.substring(0, url.indexOf("#"));
} }
p = this.context.fetchResource(StructureDefinition.class, typeProfile); p = this.context.fetchResource(StructureDefinition.class, typeProfile);
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown profile " + typeProfile)) { if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, "Unknown profile " + typeProfile)) {
List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>(); List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.element, type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension); validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
if (hasErrors(profileErrors)) if (hasErrors(profileErrors))
badProfiles.put(typeProfile, profileErrors); badProfiles.put(typeProfile, profileErrors);
else else
@ -4970,7 +4970,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (goodProfiles.size()==1) { if (goodProfiles.size()==1) {
errors.addAll(goodProfiles.values().iterator().next()); errors.addAll(goodProfiles.values().iterator().next());
} else if (goodProfiles.size()==0) { } else if (goodProfiles.size()==0) {
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, false, "Unable to find matching profile among choices: " + StringUtils.join("; ", profiles)); rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, "Unable to find matching profile among choices: " + StringUtils.join("; ", profiles));
for (String m : badProfiles.keySet()) { for (String m : badProfiles.keySet()) {
p = this.context.fetchResource(StructureDefinition.class, m); p = this.context.fetchResource(StructureDefinition.class, m);
for (ValidationMessage message : badProfiles.get(m)) { for (ValidationMessage message : badProfiles.get(m)) {
@ -4979,7 +4979,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} }
} }
} else { } else {
warning(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, false, "Found multiple matching profiles among choices: " + StringUtils.join("; ", goodProfiles.keySet())); warning(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), false, "Found multiple matching profiles among choices: " + StringUtils.join("; ", goodProfiles.keySet()));
for (String m : goodProfiles.keySet()) { for (String m : goodProfiles.keySet()) {
p = this.context.fetchResource(StructureDefinition.class, m); p = this.context.fetchResource(StructureDefinition.class, m);
for (ValidationMessage message : goodProfiles.get(m)) { for (ValidationMessage message : goodProfiles.get(m)) {
@ -4993,16 +4993,16 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
trackUsage(p, hostContext, element); trackUsage(p, hostContext, element);
if (!elementValidated) { if (!elementValidated) {
if (ei.element.getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.element.getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.element.getSpecial() == SpecialElement.PARAMETER ) if (ei.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || ei.getElement().getSpecial() == SpecialElement.BUNDLE_OUTCOME || ei.getElement().getSpecial() == SpecialElement.PARAMETER )
validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, ei.definition, ei.element, ei.element, type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension); validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, ei.definition, ei.getElement(), ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
else else
validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.element, type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension); validateElement(hostContext, errors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
} }
int index = profile.getSnapshot().getElement().indexOf(ei.definition); int index = profile.getSnapshot().getElement().indexOf(ei.definition);
if (index < profile.getSnapshot().getElement().size() - 1) { if (index < profile.getSnapshot().getElement().size() - 1) {
String nextPath = profile.getSnapshot().getElement().get(index+1).getPath(); String nextPath = profile.getSnapshot().getElement().get(index+1).getPath();
if (!nextPath.equals(ei.definition.getPath()) && nextPath.startsWith(ei.definition.getPath())) if (!nextPath.equals(ei.definition.getPath()) && nextPath.startsWith(ei.definition.getPath()))
validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.element, type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension); validateElement(hostContext, errors, profile, ei.definition, null, null, resource, ei.getElement(), type, localStack, thisIsCodeableConcept, checkDisplay, thisExtension);
} }
} }
} }
@ -5065,13 +5065,11 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
profile.setUserData("usesMustSupport", usesMustSupport); profile.setUserData("usesMustSupport", usesMustSupport);
} }
if (usesMustSupport.equals("Y")) { if (usesMustSupport.equals("Y")) {
String elementSupported = ei.element.getUserString("elementSupported"); String elementSupported = ei.getElement().getUserString("elementSupported");
if (elementSupported==null || ei.definition.getMustSupport()) if (elementSupported==null || ei.definition.getMustSupport())
if (ei.definition.getMustSupport()) { if (ei.definition.getMustSupport()) {
ei.element.setUserData("elementSupported", "Y"); ei.getElement().setUserData("elementSupported", "Y");
} }
// else
// ei.element.setUserData("elementSupported", "N");
} }
} }
@ -5164,16 +5162,16 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (ei.additionalSlice && ei.definition != null) { if (ei.additionalSlice && ei.definition != null) {
if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) ||
ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true /* TODO: replace "true" with condition to check that this element is at "end" */) { ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPENATEND) && true /* TODO: replace "true" with condition to check that this element is at "end" */) {
slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.path, false, "This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl()), slicingHint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.getPath(), false, "This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl()),
"This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl()+": "+errorSummaryForSlicingAsHtml(ei.sliceInfo))); "This element does not match any known slice" + (profile == null ? "" : " defined in the profile " + profile.getUrl()+": "+errorSummaryForSlicingAsHtml(ei.sliceInfo)));
} else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) { } else if (ei.definition.getSlicing().getRules().equals(ElementDefinition.SlicingRules.CLOSED)) {
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, false, "This element does not match any known slice " + (profile == null ? "" : " defined in the profile " + profile.getUrl() + " and slicing is CLOSED: "+errorSummaryForSlicing(ei.sliceInfo)), rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), false, "This element does not match any known slice " + (profile == null ? "" : " defined in the profile " + profile.getUrl() + " and slicing is CLOSED: "+errorSummaryForSlicing(ei.sliceInfo)),
"This element does not match any known slice " + (profile == null ? "" : " defined in the profile " + profile.getUrl() + " and slicing is CLOSED: "+errorSummaryForSlicingAsHtml(ei.sliceInfo))); "This element does not match any known slice " + (profile == null ? "" : " defined in the profile " + profile.getUrl() + " and slicing is CLOSED: "+errorSummaryForSlicingAsHtml(ei.sliceInfo)));
} }
} else { } else {
// Don't raise this if we're in an abstract profile, like Resource // Don't raise this if we're in an abstract profile, like Resource
if (!profile.getAbstract()) if (!profile.getAbstract())
rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.path, (ei.definition != null), "This element is not allowed by the profile "+profile.getUrl()); rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.getPath(), (ei.definition != null), "This element is not allowed by the profile "+profile.getUrl());
} }
// TODO: Should get the order of elements correct when parsing elements that are XML attributes vs. elements // TODO: Should get the order of elements correct when parsing elements that are XML attributes vs. elements
boolean isXmlAttr = false; boolean isXmlAttr = false;
@ -5188,10 +5186,10 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (!ToolingExtensions.readBoolExtension(profile, "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-no-order")) { if (!ToolingExtensions.readBoolExtension(profile, "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-no-order")) {
boolean ok = (ei.definition == null) || (ei.index >= last) || isXmlAttr; boolean ok = (ei.definition == null) || (ei.index >= last) || isXmlAttr;
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, ok, "As specified by profile " + profile.getUrl() + ", Element '"+ei.name+"' is out of order"); rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), ok, "As specified by profile " + profile.getUrl() + ", Element '"+ei.getName()+"' is out of order");
} }
if (ei.slice != null && ei.index == last && ei.slice.getSlicing().getOrdered()) if (ei.slice != null && ei.index == last && ei.slice.getSlicing().getOrdered())
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, (ei.definition == null) || (ei.sliceindex >= lastSlice) || isXmlAttr, "As specified by profile " + profile.getUrl() + ", Element '"+ei.name+"' is out of order in ordered slice"); rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), (ei.definition == null) || (ei.sliceindex >= lastSlice) || isXmlAttr, "As specified by profile " + profile.getUrl() + ", Element '"+ei.getName()+"' is out of order in ordered slice");
if (ei.definition == null || !isXmlAttr) if (ei.definition == null || !isXmlAttr)
last = ei.index; last = ei.index;
if (ei.slice != null) if (ei.slice != null)
@ -5220,11 +5218,11 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
boolean childUnsupportedSlicing, ElementInfo ei) { boolean childUnsupportedSlicing, ElementInfo ei) {
boolean match = false; boolean match = false;
if (slicer == null || slicer == ed) { if (slicer == null || slicer == ed) {
match = nameMatches(ei.name, tail(ed.getPath())); match = nameMatches(ei.getName(), tail(ed.getPath()));
} else { } else {
if (nameMatches(ei.name, tail(ed.getPath()))) if (nameMatches(ei.getName(), tail(ed.getPath())))
try { try {
match = sliceMatches(hostContext, ei.element, ei.path, slicer, ed, profile, errors, sliceInfo, stack); match = sliceMatches(hostContext, ei.getElement(), ei.getPath(), slicer, ed, profile, errors, sliceInfo, stack);
if (match) { if (match) {
ei.slice = slicer; ei.slice = slicer;
@ -5235,14 +5233,14 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
ei.additionalSlice = true; ei.additionalSlice = true;
} }
} catch (FHIRException e) { } catch (FHIRException e) {
rule(errors, IssueType.PROCESSING, ei.line(), ei.col(), ei.path, false, e.getMessage()); rule(errors, IssueType.PROCESSING, ei.line(), ei.col(), ei.getPath(), false, e.getMessage());
unsupportedSlicing = true; unsupportedSlicing = true;
childUnsupportedSlicing = true; childUnsupportedSlicing = true;
} }
} }
if (match) { if (match) {
boolean isOk = ei.definition == null || ei.definition == slicer || (ei.definition.getPath().endsWith("[x]") && ed.getPath().startsWith(ei.definition.getPath().replace("[x]", ""))); boolean isOk = ei.definition == null || ei.definition == slicer || (ei.definition.getPath().endsWith("[x]") && ed.getPath().startsWith(ei.definition.getPath().replace("[x]", "")));
if (rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, isOk, "Profile " + profile.getUrl() + ", Element matches more than one slice - " + (ei.definition==null || !ei.definition.hasSliceName() ? "" : ei.definition.getSliceName()) + ", " + (ed.hasSliceName() ? ed.getSliceName() : ""))) { if (rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.getPath(), isOk, "Profile " + profile.getUrl() + ", Element matches more than one slice - " + (ei.definition==null || !ei.definition.hasSliceName() ? "" : ei.definition.getSliceName()) + ", " + (ed.hasSliceName() ? ed.getSliceName() : ""))) {
ei.definition = ed; ei.definition = ed;
if (ei.slice == null) { if (ei.slice == null) {
ei.index = i; ei.index = i;
@ -5268,7 +5266,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} }
private IdStatus idStatusForEntry(Element ep, ElementInfo ei) { private IdStatus idStatusForEntry(Element ep, ElementInfo ei) {
if (isBundleEntry(ei.path)) { if (isBundleEntry(ei.getPath())) {
Element req = ep.getNamedChild("request"); Element req = ep.getNamedChild("request");
Element resp = ep.getNamedChild("response"); Element resp = ep.getNamedChild("response");
Element fullUrl = ep.getNamedChild("fullUrl"); Element fullUrl = ep.getNamedChild("fullUrl");
@ -5299,7 +5297,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
else // actually, we should never get to here; a bundle entry with method get/delete should not have a resource else // actually, we should never get to here; a bundle entry with method get/delete should not have a resource
return IdStatus.OPTIONAL; return IdStatus.OPTIONAL;
} }
} else if (isParametersEntry(ei.path) || isBundleOutcome(ei.path)) } else if (isParametersEntry(ei.getPath()) || isBundleOutcome(ei.getPath()))
return IdStatus.OPTIONAL; return IdStatus.OPTIONAL;
else else
return IdStatus.REQUIRED; return IdStatus.REQUIRED;

View File

@ -0,0 +1,131 @@
package org.hl7.fhir.r5.validation.instancevalidator.utils;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import java.util.List;
public class ElementInfo {
public List<ValidationMessage> sliceInfo;
public int index; // order of definition in overall order. all slices get the index of the slicing definition
public int sliceindex; // order of the definition in the slices (if slice != null)
public int count;
public ElementDefinition definition;
public ElementDefinition slice;
public boolean additionalSlice; // If true, indicates that this element is an additional slice
private Element element;
private String name;
private String path;
public ElementInfo(String name, Element element, String path, int count) {
this.name = name;
this.element = element;
this.path = path;
this.count = count;
}
public List<ValidationMessage> getSliceInfo() {
return sliceInfo;
}
public ElementInfo setSliceInfo(List<ValidationMessage> sliceInfo) {
this.sliceInfo = sliceInfo;
return this;
}
public int getIndex() {
return index;
}
public ElementInfo setIndex(int index) {
this.index = index;
return this;
}
public int getSliceindex() {
return sliceindex;
}
public ElementInfo setSliceindex(int sliceindex) {
this.sliceindex = sliceindex;
return this;
}
public int getCount() {
return count;
}
public ElementInfo setCount(int count) {
this.count = count;
return this;
}
public ElementDefinition getDefinition() {
return definition;
}
public ElementInfo setDefinition(ElementDefinition definition) {
this.definition = definition;
return this;
}
public ElementDefinition getSlice() {
return slice;
}
public ElementInfo setSlice(ElementDefinition slice) {
this.slice = slice;
return this;
}
public boolean isAdditionalSlice() {
return additionalSlice;
}
public ElementInfo setAdditionalSlice(boolean additionalSlice) {
this.additionalSlice = additionalSlice;
return this;
}
public Element getElement() {
return element;
}
public ElementInfo setElement(Element element) {
this.element = element;
return this;
}
public String getName() {
return name;
}
public ElementInfo setName(String name) {
this.name = name;
return this;
}
public String getPath() {
return path;
}
public ElementInfo setPath(String path) {
this.path = path;
return this;
}
public int col() {
return element.col();
}
public int line() {
return element.line();
}
@Override
public String toString() {
return path;
}
}