This commit is contained in:
Grahame Grieve 2023-10-31 17:00:59 +11:00
parent 6c878dd9c0
commit 89fc407479
1 changed files with 69 additions and 3 deletions

View File

@ -38,6 +38,7 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
@ -46,6 +47,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
import org.hl7.fhir.validation.instance.utils.ValidationContext;
public class StructureDefinitionValidator extends BaseValidator { public class StructureDefinitionValidator extends BaseValidator {
@ -152,6 +154,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
} }
} }
List<Element> extensions = src.getChildren("extension"); List<Element> extensions = src.getChildren("extension");
int c = 0; int c = 0;
for (Element extension : extensions) { for (Element extension : extensions) {
@ -160,6 +163,13 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
c++; c++;
} }
List<Element> contextInvariants = src.getChildren("contextInvariant");
c = 0;
for (Element contextInvariant : contextInvariants) {
ok = validateContextInvariant(errors, contextInvariant, src, stack.push(contextInvariant, c, null, null)) && ok;
c++;
}
// if this is defining an extension, make sure that the extension fixed value matches the URL // 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");
@ -344,7 +354,7 @@ public class StructureDefinitionValidator extends BaseValidator {
cv = ec.primitiveValue(); cv = ec.primitiveValue();
} }
if ("element".equals(ct) && "Element".equals(cv)) { 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); warning(errors, "2023-04-23", IssueType.BUSINESSRULE, n.getLiteralPath(), false, I18nConstants.SD_CONTEXT_SHOULD_NOT_BE_ELEMENT, cv, src.getNamedChildValue("id"));
} }
} else { } else {
ok = rule(errors, "2023-04-23", IssueType.INVALID, n.getLiteralPath(), false, I18nConstants.SD_NO_CONTEXT_WHEN_NOT_EXTENSION, type) && ok; ok = rule(errors, "2023-04-23", IssueType.INVALID, n.getLiteralPath(), false, I18nConstants.SD_NO_CONTEXT_WHEN_NOT_EXTENSION, type) && ok;
@ -545,10 +555,11 @@ public class StructureDefinitionValidator extends BaseValidator {
types.add(elements.get(0).getNamedChildValue("path")); types.add(elements.get(0).getNamedChildValue("path"));
} }
List<String> warnings = new ArrayList<>(); List<String> warnings = new ArrayList<>();
ValidationContext vc = new ValidationContext(invariant);
if (Utilities.existsInList(rootPath, context.getResourceNames())) { if (Utilities.existsInList(rootPath, context.getResourceNames())) {
fpe.checkOnTypes(invariant, rootPath, types, fpe.parse(exp), warnings); fpe.checkOnTypes(vc, rootPath, types, fpe.parse(exp), warnings);
} else { } else {
fpe.checkOnTypes(invariant, "DomainResource", types, fpe.parse(exp), warnings); fpe.checkOnTypes(vc, "DomainResource", types, fpe.parse(exp), warnings);
} }
for (String s : warnings) { for (String s : warnings) {
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, key+": "+s); warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, key+": "+s);
@ -571,6 +582,61 @@ public class StructureDefinitionValidator extends BaseValidator {
return ok; return ok;
} }
private boolean validateContextInvariant(List<ValidationMessage> errors, Element invariant, Element sd, NodeStack stack) {
boolean ok = true;
String expression = invariant.getValue();
if (!Utilities.noString(expression)) {
// we have to figure out the context, and we might be in type slicing.
String exp = expression;
List<String> types = listTypeContexts(sd);
if (types.size() == 0) {
hint(errors, "2023-10-31", IssueType.INFORMATIONAL, stack, false, I18nConstants.UNABLE_TO_DETERMINE_TYPE_CONTEXT_INV, listContexts(sd));
} else
try {
List<String> warnings = new ArrayList<>();
ValidationContext vc = new ValidationContext(invariant);
fpe.checkOnTypes(vc, "DomainResource", types, fpe.parse(exp), warnings);
for (String s : warnings) {
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, s);
}
} catch (Exception e) {
if (debug) {
e.printStackTrace();
}
ok = rule(errors, "2023-06-19", IssueType.INVALID, stack, false, I18nConstants.ED_CONTEXT_INVARIANT_EXPRESSION_ERROR, expression, e.getMessage()) && ok;
}
}
return ok;
}
private Object listContexts(Element sd) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Element e : sd.getChildren("context")) {
b.append(e.getNamedChildValue("type")+"="+e.getNamedChildValue("expression"));
}
return b.toString();
}
private List<String> listTypeContexts(Element sd) {
List<String> types = new ArrayList<>();
for (Element e : sd.getChildren("context")) {
switch (e.getNamedChildValue("type")) {
case "fhirpath" :
break;
case "element" :
types.add(e.getNamedChildValue("expression"));
break;
case "extension" :
// this isn't defined?
types.add(e.getNamedChildValue("Extension"));
types.add(e.getNamedChildValue("Extension.value"));
break;
default:
}
}
return types;
}
private boolean haseHasInvariant(StructureDefinition base, String key) { private boolean haseHasInvariant(StructureDefinition base, String key) {
for (ElementDefinition ed : base.getSnapshot().getElement()) { for (ElementDefinition ed : base.getSnapshot().getElement()) {
for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) { for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) {