Deal with choices that constrain elements and not types

This commit is contained in:
Grahame Grieve 2020-01-29 19:32:43 +11:00
parent e286d5b7bb
commit 01c5789b89
2 changed files with 44 additions and 13 deletions

View File

@ -4674,16 +4674,14 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (childDefinitions.isEmpty()) { if (childDefinitions.isEmpty()) {
if (actualType == null) if (actualType == null)
return; // there'll be an error elsewhere in this case, and we're going to stop. return; // there'll be an error elsewhere in this case, and we're going to stop.
StructureDefinition dt = null; childDefinitions = getActualTypeChildren(hostContext, element, actualType);
if (isAbsolute(actualType)) } else if (definition.getType().size() > 1) {
dt = this.context.fetchResource(StructureDefinition.class, actualType); // this only happens when the profile constrains the abstract children but leaves th choice open.
else if (actualType == null)
dt = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + actualType); return; // there'll be an error elsewhere in this case, and we're going to stop.
if (dt == null) List<ElementDefinition> typeChildDefinitions = getActualTypeChildren(hostContext, element, actualType);
throw new DefinitionException("Unable to resolve actual type " + actualType); // what were going to do is merge them - the type is not allowed to constrain things that the child definitions already do (well, if it does, it'll be ignored)
trackUsage(dt, hostContext, element); mergeChildLists(childDefinitions, typeChildDefinitions, definition.getPath(), actualType);
childDefinitions = ProfileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0));
} }
List<ElementInfo> children = listChildren(element, stack); List<ElementInfo> children = listChildren(element, stack);
@ -4698,6 +4696,39 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} }
} }
private void mergeChildLists(List<ElementDefinition> master, List<ElementDefinition> additional, String masterPath, String typePath) {
for (ElementDefinition ed : additional) {
boolean inMaster = false;
for (ElementDefinition t : master) {
String tp = masterPath + ed.getPath().substring(typePath.length());
if (t.getPath().equals(tp)) {
inMaster = true;
}
}
if (!inMaster) {
master.add(ed);
}
}
}
// todo: the element definition in context might assign a constrained profile for the type?
public List<ElementDefinition> getActualTypeChildren(ValidatorHostContext hostContext, Element element, String actualType) {
List<ElementDefinition> childDefinitions;
StructureDefinition dt = null;
if (isAbsolute(actualType))
dt = this.context.fetchResource(StructureDefinition.class, actualType);
else
dt = this.context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + actualType);
if (dt == null)
throw new DefinitionException("Unable to resolve actual type " + actualType);
trackUsage(dt, hostContext, element);
childDefinitions = ProfileUtilities.getChildMap(dt, dt.getSnapshot().getElement().get(0));
return childDefinitions;
}
public void checkChild(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition, public void checkChild(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition,
Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl) Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl)
throws FHIRException, DefinitionException { throws FHIRException, DefinitionException {
@ -5079,7 +5110,7 @@ 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()+": "+errorSummaryForSlicing(ei.sliceInfo)), 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())+": "+errorSummaryForSlicing(ei.sliceInfo),
"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.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)),
@ -5088,7 +5119,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
} 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())
hint(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.path, (ei.definition != null), "Could not verify slice for profile " + profile.getUrl()); rule(errors, IssueType.NOTSUPPORTED, ei.line(), ei.col(), ei.path, (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;

View File

@ -17,7 +17,7 @@
<properties> <properties>
<hapi_fhir_version>4.1.0</hapi_fhir_version> <hapi_fhir_version>4.1.0</hapi_fhir_version>
<validator_test_case_version>1.0.35-SNAPSHOT</validator_test_case_version> <validator_test_case_version>1.0.36-SNAPSHOT</validator_test_case_version>
</properties> </properties>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>