Add more validation around ValueSet.compose.include.system - must be a proper URL, and not a reference to a supplement
This commit is contained in:
parent
51f5309cc7
commit
0f08bb4e49
|
@ -1060,6 +1060,15 @@ public class I18nConstants {
|
|||
public static final String UNABLE_TO_INFER_CODESYSTEM = "UNABLE_TO_INFER_CODESYSTEM";
|
||||
public static final String CODE_CASE_DIFFERENCE = "CODE_CASE_DIFFERENCE";
|
||||
public static final String ILLEGAL_PROPERTY = "ILLEGAL_PROPERTY";
|
||||
public static final String VALUESET_INCLUDE_SYSTEM_ABSOLUTE = "VALUESET_INCLUDE_SYSTEM_ABSOLUTE";
|
||||
public static final String VALUESET_INCLUDE_SYSTEM_ABSOLUTE_FRAG = "VALUESET_INCLUDE_SYSTEM_ABSOLUTE_FRAG";
|
||||
public static final String CODESYSTEM_CS_NO_VS_SUPPLEMENT1 = "CODESYSTEM_CS_NO_VS_SUPPLEMENT1";
|
||||
public static final String CODESYSTEM_CS_NO_VS_SUPPLEMENT2 = "CODESYSTEM_CS_NO_VS_SUPPLEMENT2";
|
||||
public static final String CODESYSTEM_CS_SUPP_NO_SUPP = "CODESYSTEM_CS_SUPP_NO_SUPP";
|
||||
public static final String VALUESET_INCLUDE_CS_CONTENT = "VALUESET_INCLUDE_CS_CONTENT";
|
||||
public static final String VALUESET_INCLUDE_CSVER_CONTENT = "VALUESET_INCLUDE_CSVER_CONTENT";
|
||||
public static final String VALUESET_INCLUDE_CS_SUPPLEMENT = "VALUESET_INCLUDE_CS_SUPPLEMENT";
|
||||
public static final String VALUESET_INCLUDE_CSVER_SUPPLEMENT = "VALUESET_INCLUDE_CSVER_SUPPLEMENT";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -551,6 +551,8 @@ XHTML_URL_INVALID_CHARS_one = URL contains Invalid Character ({1})
|
|||
XHTML_URL_INVALID_CHARS_other = URL contains {0} Invalid Characters ({1})
|
||||
TERMINOLOGY_TX_SYSTEM_HTTPS = The system URL ''{0}'' wrongly starts with https: not http:
|
||||
CODESYSTEM_CS_NO_VS_NOTCOMPLETE = Review the All Codes Value Set - incomplete CodeSystems generally should not have an all codes value set specified
|
||||
CODESYSTEM_CS_NO_VS_SUPPLEMENT1 = CodeSystems supplements should not have an all codes value set specified, and if they do, it must match the base code system
|
||||
CODESYSTEM_CS_NO_VS_SUPPLEMENT2 = CodeSystems supplements should not have an all codes value set specified, and if they do, it must match the base code system, and this one does not (''{0}'')
|
||||
TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_IETF_SYSTEM_VALUE = if identifier.system is ''urn:ietf:rfc:3986'', then the identifier.value must be a full URI (e.g. start with a scheme), not ''{0}''
|
||||
TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID = Stated Attachment Size {0} is not valid
|
||||
TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_CORRECT = Stated Attachment Size {0} does not match actual attachment size {1}
|
||||
|
@ -1056,7 +1058,6 @@ VALUESET_CIRCULAR_REFERENCE = Found a circularity pointing to {0} processing Val
|
|||
VALUESET_SUPPLEMENT_MISSING_one = Required supplement not found: {1}
|
||||
VALUESET_SUPPLEMENT_MISSING_other = Required supplements not found: {1}
|
||||
CONCEPTMAP_VS_TOO_MANY_CODES = The concept map has too many codes to validate ({0})
|
||||
CONCEPTMAP_VS_CONCEPT_CODE_UNKNOWN_SYSTEM = The code ''{1}'' comes from the system {0} which could not be found, so it''s not known whether it''s valid in the value set ''{2}''
|
||||
CONCEPTMAP_VS_INVALID_CONCEPT_CODE = The code ''{1}'' in the system {0} is not valid in the value set ''{2}''
|
||||
CONCEPTMAP_VS_INVALID_CONCEPT_CODE_VER = The code ''{2}'' in the system {0} version {1} is not valid in the value set ''{3}''
|
||||
VALUESET_INC_TOO_MANY_CODES = The value set include has too many codes to validate ({0}), so each individual code has not been checked
|
||||
|
@ -1118,3 +1119,11 @@ VALUESET_INCLUDE_CSVER_MULTI_FOUND = Multiple matching contained code systems fo
|
|||
CODE_CASE_DIFFERENCE = The code ''{0}'' differs from the correct code ''{1}'' by case. Although the code system ''{2}'' is case insensitive, implementers are strongly encouraged to use the correct case anyway
|
||||
SCT_NO_MRCM = Not validated against the Machine Readable Concept Model (MRCM)
|
||||
ILLEGAL_PROPERTY = The property ''{0}'' is invalid
|
||||
VALUESET_INCLUDE_SYSTEM_ABSOLUTE = URI values in ValueSet.compose.include.system must be absolute
|
||||
VALUESET_INCLUDE_SYSTEM_ABSOLUTE_FRAG = URI values in ValueSet.compose.include.system must be absolute. To reference a contained code system, use the full CodeSystem URL and reference it using the http://hl7.org/fhir/StructureDefinition/valueset-system extension
|
||||
CODESYSTEM_CS_SUPP_NO_SUPP = The code system is marked as a supplement, but it does not define what code system it supplements
|
||||
VALUESET_INCLUDE_CS_CONTENT = The value set references CodeSystem ''{0}'' which has status ''{1}''
|
||||
VALUESET_INCLUDE_CSVER_CONTENT = The value set references CodeSystem ''{0}'' version ''{2}'' which has status ''{1}''
|
||||
VALUESET_INCLUDE_CS_SUPPLEMENT = The value set references CodeSystem ''{0}'' which is a supplement. It must reference the underlying CodeSystem ''{1}'' and use the http://hl7.org/fhir/StructureDefinition/valueset-supplement extension for the supplement
|
||||
VALUESET_INCLUDE_CSVER_SUPPLEMENT = The value set references CodeSystem ''{0}'' version ''{2}'' which is a supplement. It must reference the underlying CodeSystem ''{1}'' and use the http://hl7.org/fhir/StructureDefinition/valueset-supplement extension for the supplement
|
||||
|
||||
|
|
|
@ -33,7 +33,20 @@ public class CodeSystemValidator extends BaseValidator {
|
|||
|
||||
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);
|
||||
if ("supplement".equals(content)) {
|
||||
CodeSystem csB = context.fetchCodeSystem(supp);
|
||||
if (csB != null) {
|
||||
if (csB.hasValueSet()) {
|
||||
warning(errors, "2024-03-06", IssueType.BUSINESSRULE, stack.getLiteralPath(), vsu.equals(vsu), I18nConstants.CODESYSTEM_CS_NO_VS_SUPPLEMENT2, csB.getValueSet());
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NO_VS_SUPPLEMENT1);
|
||||
}
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE);
|
||||
}
|
||||
} else {
|
||||
hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE);
|
||||
}
|
||||
ValueSet vs;
|
||||
try {
|
||||
vs = context.fetchResourceWithException(ValueSet.class, vsu);
|
||||
|
@ -61,22 +74,26 @@ public class CodeSystemValidator extends BaseValidator {
|
|||
}
|
||||
} // todo... try getting the value set the other way...
|
||||
|
||||
if (supp != null) {
|
||||
if (context.supportsSystem(supp, options.getFhirVersion())) {
|
||||
List<Element> concepts = cs.getChildrenByName("concept");
|
||||
int ce = 0;
|
||||
for (Element concept : concepts) {
|
||||
NodeStack nstack = stack.push(concept, ce, null, null);
|
||||
if (ce == 0) {
|
||||
rule(errors, "2023-08-15", IssueType.INVALID, nstack, !"not-present".equals(content), I18nConstants.CODESYSTEM_CS_COUNT_NO_CONTENT_ALLOWED);
|
||||
if ("supplement".equals(content) || supp != null) {
|
||||
if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, stack.getLiteralPath(), !Utilities.noString(supp), I18nConstants.CODESYSTEM_CS_SUPP_NO_SUPP)) {
|
||||
if (context.supportsSystem(supp, options.getFhirVersion())) {
|
||||
List<Element> concepts = cs.getChildrenByName("concept");
|
||||
int ce = 0;
|
||||
for (Element concept : concepts) {
|
||||
NodeStack nstack = stack.push(concept, ce, null, null);
|
||||
if (ce == 0) {
|
||||
rule(errors, "2023-08-15", IssueType.INVALID, nstack, !"not-present".equals(content), I18nConstants.CODESYSTEM_CS_COUNT_NO_CONTENT_ALLOWED);
|
||||
}
|
||||
ok = validateSupplementConcept(errors, concept, nstack, supp, options) && ok;
|
||||
ce++;
|
||||
}
|
||||
} else {
|
||||
if (cs.hasChildren("concept")) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_SUPP_CANT_CHECK, supp);
|
||||
}
|
||||
ok = validateSupplementConcept(errors, concept, nstack, supp, options) && ok;
|
||||
ce++;
|
||||
}
|
||||
} else {
|
||||
if (cs.hasChildren("concept")) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_SUPP_CANT_CHECK, supp);
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.hl7.fhir.validation.instance.type;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
@ -141,23 +142,26 @@ public class ValueSetValidator extends BaseValidator {
|
|||
if (valuesets.size() > 1) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, stack.getLiteralPath(), false, I18nConstants.VALUESET_IMPORT_UNION_INTERSECTION);
|
||||
}
|
||||
if (system != null && system.startsWith("#")) {
|
||||
List<Element> cs = new ArrayList<>();
|
||||
for (Element contained : vsSrc.getChildrenByName("contained")) {
|
||||
if (("#"+contained.getIdBase()).equals(system)) {
|
||||
if (rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), "CodeSystem".equals(contained.fhirType()), I18nConstants.VALUESET_INCLUDE_CS_NOT_CS, system, contained.fhirType())) {
|
||||
if (version == null || version.equals(contained.getChildValue("version"))) {
|
||||
cs.add(contained);
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
if (system != null) {
|
||||
rule(errors, "2024-03-06", IssueType.INVALID, stack.getLiteralPath(), Utilities.isAbsoluteUrl(system), system.startsWith("#") ? I18nConstants.VALUESET_INCLUDE_SYSTEM_ABSOLUTE_FRAG : I18nConstants.VALUESET_INCLUDE_SYSTEM_ABSOLUTE, system);
|
||||
if (system.startsWith("#")) {
|
||||
List<Element> cs = new ArrayList<>();
|
||||
for (Element contained : vsSrc.getChildrenByName("contained")) {
|
||||
if (("#"+contained.getIdBase()).equals(system)) {
|
||||
ok = false; // see absolute check above.
|
||||
|
||||
if (rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), "CodeSystem".equals(contained.fhirType()), I18nConstants.VALUESET_INCLUDE_CS_NOT_CS, system, contained.fhirType())) {
|
||||
if (version == null || version.equals(contained.getChildValue("version"))) {
|
||||
cs.add(contained);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cs.isEmpty()) {
|
||||
ok = rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), false, version == null ? I18nConstants.VALUESET_INCLUDE_CS_NOT_FOUND : I18nConstants.VALUESET_INCLUDE_CSVER_NOT_FOUND, system, version) && ok;
|
||||
} else {
|
||||
ok = rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), cs.size() == 1, version == null ? I18nConstants.VALUESET_INCLUDE_CS_MULTI_FOUND : I18nConstants.VALUESET_INCLUDE_CSVER_MULTI_FOUND, system, version) && ok;
|
||||
if (cs.isEmpty()) {
|
||||
ok = rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), false, version == null ? I18nConstants.VALUESET_INCLUDE_CS_NOT_FOUND : I18nConstants.VALUESET_INCLUDE_CSVER_NOT_FOUND, system, version) && ok;
|
||||
} else {
|
||||
ok = rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), cs.size() == 1, version == null ? I18nConstants.VALUESET_INCLUDE_CS_MULTI_FOUND : I18nConstants.VALUESET_INCLUDE_CSVER_MULTI_FOUND, system, version) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Element> concepts = include.getChildrenByName("concept");
|
||||
|
@ -165,6 +169,23 @@ public class ValueSetValidator extends BaseValidator {
|
|||
|
||||
CodeSystemChecker slv = getSystemValidator(system, errors);
|
||||
if (!Utilities.noString(system)) {
|
||||
CodeSystem cs = context.fetchCodeSystem(system, version);
|
||||
if (cs != null) { // if it's null, we can't analyse this
|
||||
switch (cs.getContent()) {
|
||||
case EXAMPLE:
|
||||
warning(errors, "2024-03-06", IssueType.INVALID, stack.getLiteralPath(), false, version == null ? I18nConstants.VALUESET_INCLUDE_CS_CONTENT : I18nConstants.VALUESET_INCLUDE_CSVER_CONTENT, system, cs.getContent().toCode(), version);
|
||||
break;
|
||||
case FRAGMENT:
|
||||
hint(errors, "2024-03-06", IssueType.INVALID, stack.getLiteralPath(), false, version == null ? I18nConstants.VALUESET_INCLUDE_CS_CONTENT : I18nConstants.VALUESET_INCLUDE_CSVER_CONTENT, system, cs.getContent().toCode(), version);
|
||||
break;
|
||||
case SUPPLEMENT:
|
||||
ok = rule(errors, "2024-03-06", IssueType.INVALID, stack.getLiteralPath(), false, version == null ? I18nConstants.VALUESET_INCLUDE_CS_SUPPLEMENT : I18nConstants.VALUESET_INCLUDE_CSVER_SUPPLEMENT, system, cs.getSupplements(), version) && ok;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean systemOk = true;
|
||||
int cc = 0;
|
||||
List<VSCodingValidationRequest> batch = new ArrayList<>();
|
||||
|
|
Loading…
Reference in New Issue