Validate that binding references are present, and are for value sets
This commit is contained in:
parent
2c4b4c4ca2
commit
1532a038c9
|
@ -352,6 +352,11 @@ public class I18nConstants {
|
|||
public static final String SD_ED_TYPE_PROFILE_WRONG = "SD_ED_TYPE_PROFILE_WRONG";
|
||||
public static final String SD_ED_TYPE_PROFILE_WRONG_TARGET = "SD_ED_TYPE_PROFILE_WRONG_TARGET";
|
||||
public static final String SD_ED_TYPE_NO_TARGET_PROFILE = "SD_ED_TYPE_NO_TARGET_PROFILE";
|
||||
public static final String SD_ED_SHOULD_BIND = "SD_ED_SHOULD_BIND";
|
||||
public static final String SD_ED_SHOULD_BIND_WITH_VS = "SD_ED_SHOULD_BIND_WITH_VS";
|
||||
public static final String SD_ED_BIND_UNKNOWN_VS = "SD_ED_BIND_UNKNOWN_VS";
|
||||
public static final String SD_ED_BIND_NOT_VS = "SD_ED_BIND_NOT_VS";
|
||||
public static final String SD_ED_BIND_NO_BINDABLE = "SD_ED_BIND_NO_BINDABLE";
|
||||
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
|
||||
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
|
||||
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";
|
||||
|
|
|
@ -628,3 +628,8 @@ XHTML_URL_DATA_NO_DATA = No data found in data: URL
|
|||
XHTML_URL_DATA_DATA_INVALID_COMMA = Comma found in data portion of data URL: {0}
|
||||
XHTML_URL_DATA_DATA_INVALID = The data should be valid base64 content for a data: URL: {0}
|
||||
XHTML_URL_DATA_MIMETYPE = The mimetype potion of the data: URL is not valid ({1}) in URL: {0}
|
||||
SD_ED_SHOULD_BIND = The element {0} has a type that should have a binding ({1}), but no binding is present
|
||||
SD_ED_SHOULD_BIND_WITH_VS = The element {0} has a type that should have a binding ({1}), but the binding has no value set
|
||||
SD_ED_BIND_UNKNOWN_VS = The valueSet reference {1} on element {0} could not be resolved
|
||||
SD_ED_BIND_NOT_VS = The valueSet reference {1} on element {0} points to something that is not a value set ({2})
|
||||
SD_ED_BIND_NO_BINDABLE = The element {0} has a binding, but no bindable types are present {1}
|
|
@ -4,7 +4,9 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.convertors.VersionConvertor_10_50;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_14_50;
|
||||
|
@ -19,12 +21,15 @@ import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
|||
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
@ -115,10 +120,12 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
private void validateElementDefinition(List<ValidationMessage> errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd) {
|
||||
boolean typeMustSupport = false;
|
||||
List<Element> types = element.getChildrenByName("type");
|
||||
Set<String> typeCodes = new HashSet<>();
|
||||
for (Element type : types) {
|
||||
if (hasMustSupportExtension(type)) {
|
||||
typeMustSupport = true;
|
||||
}
|
||||
typeCodes.add(type.getChildValue("code"));
|
||||
// check the stated profile - must be a constraint on the type
|
||||
if (snapshot || sd != null) {
|
||||
validateElementType(errors, type, stack.push(type, -1, null, null), sd, element.getChildValue("path"));
|
||||
|
@ -131,6 +138,50 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path"));
|
||||
}
|
||||
}
|
||||
if (element.hasChild("binding")) {
|
||||
Element binding = element.getNamedChild("binding");
|
||||
validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, element.getNamedChildValue("path"));
|
||||
} 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, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
|
||||
}
|
||||
}
|
||||
|
||||
private String boundType(Set<String> typeCodes) {
|
||||
for (String tc : typeCodes) {
|
||||
if (Utilities.existsInList(tc, "code", "Coding", "CodeableConcept", "Quantity", "CodeableReference")) {
|
||||
return tc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String bindableType(Set<String> typeCodes) {
|
||||
String ret = boundType(typeCodes);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
for (String tc : typeCodes) {
|
||||
if (Utilities.existsInList(tc, "string", "uri", "CodeableConcept", "Quantity", "CodeableReference")) {
|
||||
return tc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void validateBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, Set<String> typeCodes, boolean snapshot, String path) {
|
||||
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bindableType(typeCodes) != null, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString());
|
||||
if (binding.hasChild("valueSet")) {
|
||||
Element valueSet = binding.getNamedChild("valueSet");
|
||||
String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("refernece");
|
||||
if (warning(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) {
|
||||
Resource vs = context.fetchResource(Resource.class, ref);
|
||||
if (warning(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null, I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) {
|
||||
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateElementType(List<ValidationMessage> errors, Element type, NodeStack stack, StructureDefinition sd, String path) {
|
||||
|
@ -231,9 +282,11 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
String t = determineBaseType(sd);
|
||||
if (t == null) {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), code.equals(t), I18nConstants.SD_ED_TYPE_PROFILE_NOTYPE, p);
|
||||
} else if (!VersionUtilities.isR5Ver(context.getVersion())) {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t) || "Resource".equals(t), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
|
||||
} else {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(t), I18nConstants.SD_ED_TYPE_PROFILE_WRONG_TARGET, p, t, code, path, "Canonical Resource");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.SD_ED_TYPE_NO_TARGET_PROFILE, code);
|
||||
|
|
Loading…
Reference in New Issue