CodeSystem validation - properties and designations
This commit is contained in:
parent
a51c3f96ad
commit
33a1814d4e
|
@ -1072,6 +1072,21 @@ public class I18nConstants {
|
||||||
public static final String CODESYSTEM_SUPP_NO_DISPLAY = "CODESYSTEM_SUPP_NO_DISPLAY";
|
public static final String CODESYSTEM_SUPP_NO_DISPLAY = "CODESYSTEM_SUPP_NO_DISPLAY";
|
||||||
public static final String CODESYSTEM_NOT_CONTAINED = "CODESYSTEM_NOT_CONTAINED";
|
public static final String CODESYSTEM_NOT_CONTAINED = "CODESYSTEM_NOT_CONTAINED";
|
||||||
public static final String CODESYSTEM_THO_CHECK = "CODESYSTEM_THO_CHECK";
|
public static final String CODESYSTEM_THO_CHECK = "CODESYSTEM_THO_CHECK";
|
||||||
|
public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_DUPLICATE_URI = "CODESYSTEM_PROPERTY_DUPLICATE_URI";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_BAD_HL7_URI = "CODESYSTEM_PROPERTY_BAD_HL7_URI";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_SYNONYM_DEPRECATED = "CODESYSTEM_PROPERTY_SYNONYM_DEPRECATED";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_DUPLICATE_CODE = "CODESYSTEM_PROPERTY_DUPLICATE_CODE";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_URI_CODE_MISMATCH = "CODESYSTEM_PROPERTY_URI_CODE_MISMATCH";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_URI_TYPE_MISMATCH = "CODESYSTEM_PROPERTY_URI_TYPE_MISMATCH";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_UNKNOWN_CODE = "CODESYSTEM_PROPERTY_UNKNOWN_CODE";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_KNOWN_CODE_SUGGESTIVE = "CODESYSTEM_PROPERTY_KNOWN_CODE_SUGGESTIVE";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_CODE_TYPE_MISMATCH = "CODESYSTEM_PROPERTY_CODE_TYPE_MISMATCH";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_UNDEFINED = "CODESYSTEM_PROPERTY_UNDEFINED";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_NO_VALUE = "CODESYSTEM_PROPERTY_NO_VALUE";
|
||||||
|
public static final String CODESYSTEM_PROPERTY_WRONG_TYPE = "CODESYSTEM_PROPERTY_WRONG_TYPE";
|
||||||
|
public static final String CODESYSTEM_DESIGNATION_DISP_CLASH_NO_LANG = "CODESYSTEM_DESIGNATION_DISP_CLASH_NO_LANG";
|
||||||
|
public static final String CODESYSTEM_DESIGNATION_DISP_CLASH_LANG = "CODESYSTEM_DESIGNATION_DISP_CLASH_LANG";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1109,7 +1109,7 @@ Validation_VAL_Profile_Minimum_SLICE_other = Slice ''{3}'': minimum required = {
|
||||||
FHIRPATH_UNKNOWN_EXTENSION = Reference to an unknown extension - double check that the URL ''{0}'' is correct
|
FHIRPATH_UNKNOWN_EXTENSION = Reference to an unknown extension - double check that the URL ''{0}'' is correct
|
||||||
Type_Specific_Checks_DT_XHTML_Resolve = Hyperlink ''{0}'' at ''{1}'' for ''{2}''' does not resolve
|
Type_Specific_Checks_DT_XHTML_Resolve = Hyperlink ''{0}'' at ''{1}'' for ''{2}''' does not resolve
|
||||||
Type_Specific_Checks_DT_XHTML_Resolve_Img = Image source ''{0}'' at ''{1}'' does not resolve
|
Type_Specific_Checks_DT_XHTML_Resolve_Img = Image source ''{0}'' at ''{1}'' does not resolve
|
||||||
TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES = Hyperlink ''{0}'' at ''{1}'' for ''{2}''' resolves to multiple targets
|
TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES = Hyperlink ''{0}'' at ''{1}'' for ''{2}'' resolves to multiple targets ({3})
|
||||||
CONTAINED_ORPHAN_DOM3 = The contained resource ''{0}'' is not referenced to from elsewhere in the containing resource nor does it refer to the containing resource (dom-3)
|
CONTAINED_ORPHAN_DOM3 = The contained resource ''{0}'' is not referenced to from elsewhere in the containing resource nor does it refer to the containing resource (dom-3)
|
||||||
VALUESET_INCLUDE_CS_NOT_CS = The include system ''{0}'' is a reference to a contained resource, but the contained resource with that id is not a CodeSystem, it's a {1}
|
VALUESET_INCLUDE_CS_NOT_CS = The include system ''{0}'' is a reference to a contained resource, but the contained resource with that id is not a CodeSystem, it's a {1}
|
||||||
VALUESET_INCLUDE_CS_NOT_FOUND = No matching contained code system found for system ''{0}''
|
VALUESET_INCLUDE_CS_NOT_FOUND = No matching contained code system found for system ''{0}''
|
||||||
|
@ -1129,4 +1129,19 @@ VALUESET_INCLUDE_CSVER_SUPPLEMENT = The value set references CodeSystem ''{0}''
|
||||||
CODESYSTEM_SUPP_NO_DISPLAY = This display (''{0}'') differs from that defined by the base code system (''{1}''). Both displays claim to be 'the "primary designation" for the same language (''{2}''), and the correct interpretation of this is undefined
|
CODESYSTEM_SUPP_NO_DISPLAY = This display (''{0}'') differs from that defined by the base code system (''{1}''). Both displays claim to be 'the "primary designation" for the same language (''{2}''), and the correct interpretation of this is undefined
|
||||||
CODESYSTEM_NOT_CONTAINED = CodeSystems are referred to directly from Coding.system, so it's generally best for them not to be contained resources
|
CODESYSTEM_NOT_CONTAINED = CodeSystems are referred to directly from Coding.system, so it's generally best for them not to be contained resources
|
||||||
CODESYSTEM_THO_CHECK = Most code systems defined in HL7 IGs will need to move to THO later during the process. Consider giving this code system a THO URL now (See https://confluence.hl7.org/display/TSMG/Terminology+Play+Book)
|
CODESYSTEM_THO_CHECK = Most code systems defined in HL7 IGs will need to move to THO later during the process. Consider giving this code system a THO URL now (See https://confluence.hl7.org/display/TSMG/Terminology+Play+Book)
|
||||||
|
TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS = There are multiple different potential matches for the url ''{0}''. It might be a good idea to fix to the correct version to reduce the likelihood of a wrong version being selected by an implementation/implementer. Using version ''{1}'', found versions: {2}
|
||||||
|
ABSTRACT_CODE_NOT_ALLOWED = Code ''{0}#{1}'' is abstract, and not allowed in this context
|
||||||
|
CODESYSTEM_PROPERTY_DUPLICATE_URI = A property is already defined with the URI ''{0}''
|
||||||
|
CODESYSTEM_PROPERTY_BAD_HL7_URI = Unknown CodeSystem Property ''{0}''. If you are creating your own property, do not create it in the HL7 namespace
|
||||||
|
CODESYSTEM_PROPERTY_SYNONYM_DEPRECATED = The 'synonym' property is deprecated; just create duplicate concepts
|
||||||
|
CODESYSTEM_PROPERTY_DUPLICATE_CODE = A property is already defined with the code ''{0}''
|
||||||
|
CODESYSTEM_PROPERTY_URI_CODE_MISMATCH = The URI ''{0}'' is normally assigned the code ''{1}''. Using the code ''{2}'' will usually create confusion in ValueSet filters etc
|
||||||
|
CODESYSTEM_PROPERTY_URI_TYPE_MISMATCH = Wrong type ''{2}'': The URI ''{0}'' identifies a property that has the type ''{1}''
|
||||||
|
CODESYSTEM_PROPERTY_UNKNOWN_CODE = This property has only (''{0}'') a code and no URI, so it has no clearly defined meaning in the terminology ecosystem
|
||||||
|
CODESYSTEM_PROPERTY_KNOWN_CODE_SUGGESTIVE = This property has only the standard code (''{0}'') but not the standard URI ''{1}'', so it has no clearly defined meaning in the terminology ecosystem
|
||||||
|
CODESYSTEM_PROPERTY_CODE_TYPE_MISMATCH = Wrong type ''{2}'': The code ''{0}'' identifies a property that has the type ''{1}''
|
||||||
|
CODESYSTEM_PROPERTY_UNDEFINED = The property ''{0}'' has no definition. Many terminology tools won't know what to do with it
|
||||||
|
CODESYSTEM_PROPERTY_NO_VALUE = The property ''{0}'' has no value, and cannot be understoof
|
||||||
|
CODESYSTEM_PROPERTY_WRONG_TYPE = The property ''{0}'' has the invalid type ''{1}'', when it is defined to have the type ''{2}''
|
||||||
|
CODESYSTEM_DESIGNATION_DISP_CLASH_NO_LANG = The designation ''{0}'' has no use and no language, so is not differentiated from the base display (''{1}'')
|
||||||
|
CODESYSTEM_DESIGNATION_DISP_CLASH_LANG = The designation ''{0}'' has no use and is in the same language (''{2}''), so is not differentiated from the base display (''{1}'')
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package org.hl7.fhir.validation.instance.type;
|
package org.hl7.fhir.validation.instance.type;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
@ -16,11 +19,66 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
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.type.CodeSystemValidator.KnownProperty;
|
||||||
|
import org.hl7.fhir.validation.instance.type.CodeSystemValidator.PropertyDef;
|
||||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||||
|
|
||||||
public class CodeSystemValidator extends BaseValidator {
|
public class CodeSystemValidator extends BaseValidator {
|
||||||
|
|
||||||
|
public enum KnownProperty {
|
||||||
|
Status, Inactive, EffectiveDate, DeprecationDate, RetirementDate, NotSelectable, Parent, Child, PartOf, Synonym, Comment, ItemWeight;
|
||||||
|
|
||||||
|
String getType() {
|
||||||
|
switch (this) {
|
||||||
|
case Child: return "code";
|
||||||
|
case Comment: return "string";
|
||||||
|
case DeprecationDate: return "dateTime";
|
||||||
|
case EffectiveDate: return "dateTime";
|
||||||
|
case Inactive: return "boolean";
|
||||||
|
case ItemWeight: return "decimal";
|
||||||
|
case NotSelectable: return "boolean";
|
||||||
|
case Parent: return "code";
|
||||||
|
case PartOf: return "code";
|
||||||
|
case RetirementDate: return "dateTime";
|
||||||
|
case Status: return "code";
|
||||||
|
case Synonym: return "code";
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getCode() {
|
||||||
|
return Utilities.uncapitalize(this.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String getUri() {
|
||||||
|
return "http://hl7.org/fhir/concept-properties#"+ getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyDef {
|
||||||
|
private String uri;
|
||||||
|
private String code;
|
||||||
|
private String type;
|
||||||
|
protected PropertyDef(String uri, String code, String type) {
|
||||||
|
super();
|
||||||
|
this.uri = uri;
|
||||||
|
this.code = code;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public String getUri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public CodeSystemValidator(BaseValidator parent) {
|
public CodeSystemValidator(BaseValidator parent) {
|
||||||
super(parent);
|
super(parent);
|
||||||
}
|
}
|
||||||
|
@ -114,12 +172,20 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
hint(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !isInQ && !isSuppProp, I18nConstants.CODESYSTEM_NOT_CONTAINED);
|
hint(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !isInQ && !isSuppProp, I18nConstants.CODESYSTEM_NOT_CONTAINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, PropertyDef> properties = new HashMap<>();
|
||||||
|
List<Element> propertyElements = cs.getChildrenByName("property");
|
||||||
|
int i = 0;
|
||||||
|
for (Element propertyElement : propertyElements) {
|
||||||
|
ok = checkPropertyDefinition(errors, cs, stack.push(propertyElement, i, null, null), "true".equals(caseSensitive), hierarchyMeaning, csB, propertyElement, properties) && ok;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> codes = new HashSet<>();
|
Set<String> codes = new HashSet<>();
|
||||||
|
|
||||||
List<Element> concepts = cs.getChildrenByName("concept");
|
List<Element> concepts = cs.getChildrenByName("concept");
|
||||||
int i = 0;
|
i = 0;
|
||||||
for (Element concept : concepts) {
|
for (Element concept : concepts) {
|
||||||
checkConcept(errors, cs, stack.push(concept, i, null, null), "true".equals(caseSensitive), hierarchyMeaning, csB, concept, codes);
|
ok = checkConcept(errors, cs, stack.push(concept, i, null, null), "true".equals(caseSensitive), hierarchyMeaning, csB, concept, codes, properties) && ok;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +193,134 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkConcept(List<ValidationMessage> errors, Element cs, NodeStack stack, boolean caseSensitive, String hierarchyMeaning, CodeSystem csB, Element concept, Set<String> codes) {
|
private boolean checkPropertyDefinition(List<ValidationMessage> errors, Element cs, NodeStack stack, boolean equals, String hierarchyMeaning, CodeSystem csB, Element property, Map<String, PropertyDef> properties) {
|
||||||
|
boolean ok = true;
|
||||||
|
String uri = property.getNamedChildValue("uri");
|
||||||
|
String code = property.getNamedChildValue("code");
|
||||||
|
String type = property.getNamedChildValue("type");
|
||||||
|
PropertyDef pd = new PropertyDef(uri, code, type);
|
||||||
|
KnownProperty ukp = null;
|
||||||
|
KnownProperty ckp = null;
|
||||||
|
|
||||||
|
if (uri != null) {
|
||||||
|
if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !properties.containsKey(uri), I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_URI, uri)) {
|
||||||
|
properties.put(uri, pd);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
if (uri.contains("hl7.org/fhir")) {
|
||||||
|
switch (uri) {
|
||||||
|
case "http://hl7.org/fhir/concept-properties#status" :
|
||||||
|
ukp = KnownProperty.Status;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#inactive" :
|
||||||
|
ukp = KnownProperty.Inactive;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#effectiveDate" :
|
||||||
|
ukp = KnownProperty.EffectiveDate;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#deprecationDate" :
|
||||||
|
ukp = KnownProperty.DeprecationDate;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#retirementDate" :
|
||||||
|
ukp = KnownProperty.RetirementDate;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#notSelectable" :
|
||||||
|
ukp = KnownProperty.NotSelectable;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#parent" :
|
||||||
|
ukp = KnownProperty.Parent;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#child" :
|
||||||
|
ukp = KnownProperty.Child;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#partOf" :
|
||||||
|
ukp = KnownProperty.PartOf;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#synonym" :
|
||||||
|
ukp = KnownProperty.Synonym;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#comment" :
|
||||||
|
ukp = KnownProperty.Comment;
|
||||||
|
break;
|
||||||
|
case "http://hl7.org/fhir/concept-properties#itemWeight" :
|
||||||
|
ukp = KnownProperty.ItemWeight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ok = false;
|
||||||
|
rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_PROPERTY_BAD_HL7_URI, uri);
|
||||||
|
}
|
||||||
|
warning(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), ukp != KnownProperty.Synonym, I18nConstants.CODESYSTEM_PROPERTY_SYNONYM_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (code != null) {
|
||||||
|
if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), !properties.containsKey(code), I18nConstants.CODESYSTEM_PROPERTY_DUPLICATE_CODE, code)) {
|
||||||
|
properties.put(code, pd);
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
switch (code) {
|
||||||
|
case "status" :
|
||||||
|
ckp = KnownProperty.Status;
|
||||||
|
break;
|
||||||
|
case "inactive" :
|
||||||
|
ckp = KnownProperty.Inactive;
|
||||||
|
break;
|
||||||
|
case "effectiveDate" :
|
||||||
|
ckp = KnownProperty.EffectiveDate;
|
||||||
|
break;
|
||||||
|
case "deprecationDate" :
|
||||||
|
ckp = KnownProperty.DeprecationDate;
|
||||||
|
break;
|
||||||
|
case "retirementDate" :
|
||||||
|
ckp = KnownProperty.RetirementDate;
|
||||||
|
break;
|
||||||
|
case "notSelectable" :
|
||||||
|
ckp = KnownProperty.NotSelectable;
|
||||||
|
break;
|
||||||
|
case "parent" :
|
||||||
|
ckp = KnownProperty.Parent;
|
||||||
|
break;
|
||||||
|
case "child" :
|
||||||
|
ckp = KnownProperty.Child;
|
||||||
|
break;
|
||||||
|
case "partOf" :
|
||||||
|
ckp = KnownProperty.PartOf;
|
||||||
|
break;
|
||||||
|
case "synonym" :
|
||||||
|
ckp = KnownProperty.Synonym;
|
||||||
|
break;
|
||||||
|
case "comment" :
|
||||||
|
ckp = KnownProperty.Comment;
|
||||||
|
break;
|
||||||
|
case "itemWeight" :
|
||||||
|
ckp = KnownProperty.ItemWeight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// no rules around codes...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ukp != null) {
|
||||||
|
ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), ckp == null || ckp == ukp, I18nConstants.CODESYSTEM_PROPERTY_URI_CODE_MISMATCH, uri, ukp.getCode(), code) && ok;
|
||||||
|
if (type != null) {
|
||||||
|
ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), type.equals(ukp.getType()), I18nConstants.CODESYSTEM_PROPERTY_URI_TYPE_MISMATCH, uri, ukp.getType(),type) && ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uri == null) {
|
||||||
|
if (ckp == null) {
|
||||||
|
hint(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_PROPERTY_UNKNOWN_CODE, code);
|
||||||
|
} else {
|
||||||
|
warning(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_PROPERTY_KNOWN_CODE_SUGGESTIVE, code, ckp.getUri());
|
||||||
|
if (type != null) {
|
||||||
|
warning(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), type.equals(ckp.getType()), I18nConstants.CODESYSTEM_PROPERTY_CODE_TYPE_MISMATCH, code, ckp.getType(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkConcept(List<ValidationMessage> errors, Element cs, NodeStack stack, boolean caseSensitive, String hierarchyMeaning, CodeSystem csB, Element concept, Set<String> codes, Map<String, PropertyDef> properties) {
|
||||||
|
boolean ok = true;
|
||||||
String code = concept.getNamedChildValue("code");
|
String code = concept.getNamedChildValue("code");
|
||||||
String display = concept.getNamedChildValue("display");
|
String display = concept.getNamedChildValue("display");
|
||||||
|
|
||||||
|
@ -147,14 +340,73 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
// check that all the defined properties have values
|
// check that all the defined properties have values
|
||||||
// check the designations have values, and the use/language don't conflict
|
// check the designations have values, and the use/language don't conflict
|
||||||
|
|
||||||
|
List<Element> propertyElements = concept.getChildrenByName("property");
|
||||||
List<Element> concepts = concept.getChildrenByName("concept");
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Element child : concepts) {
|
for (Element propertyElement : propertyElements) {
|
||||||
checkConcept(errors, cs, stack.push(concept, i, null, null), caseSensitive, hierarchyMeaning, csB, child, codes);
|
ok = checkPropertyValue(errors, cs, stack.push(propertyElement, i, null, null), propertyElement, properties) && ok;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Element> designations = concept.getChildrenByName("designation");
|
||||||
|
i = 0;
|
||||||
|
for (Element designation : designations) {
|
||||||
|
ok = checkDesignation(errors, cs, stack.push(designation, i, null, null), concept, designation) && ok;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Element> concepts = concept.getChildrenByName("concept");
|
||||||
|
i = 0;
|
||||||
|
for (Element child : concepts) {
|
||||||
|
ok = checkConcept(errors, cs, stack.push(concept, i, null, null), caseSensitive, hierarchyMeaning, csB, child, codes, properties) && ok;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkDesignation(List<ValidationMessage> errors, Element cs, NodeStack stack, Element concept, Element designation) {
|
||||||
|
boolean ok = true;
|
||||||
|
|
||||||
|
String rlang = cs.getNamedChildValue("language");
|
||||||
|
String display = concept.getNamedChildValue("display");
|
||||||
|
String lang = designation.getNamedChildValue("language");
|
||||||
|
List<Element> uses = new ArrayList<Element>();
|
||||||
|
designation.getNamedChildren("additionalUse", uses);
|
||||||
|
Element use = designation.getNamedChild("use");
|
||||||
|
if (use != null) {
|
||||||
|
uses.add(0, use);
|
||||||
|
}
|
||||||
|
String value = designation.getNamedChildValue("value");
|
||||||
|
|
||||||
|
if (uses.isEmpty()) {
|
||||||
|
// if we have no uses, we're kind of implying that it's the base display, so it should be the same
|
||||||
|
if (rlang == null && lang == null) {
|
||||||
|
ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), display == null || display.equals(value), I18nConstants.CODESYSTEM_DESIGNATION_DISP_CLASH_NO_LANG, value, display) && ok;
|
||||||
|
} else if (rlang != null && ((lang == null) || rlang.equals(lang))) {
|
||||||
|
ok = rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), display == null || display.equals(value), I18nConstants.CODESYSTEM_DESIGNATION_DISP_CLASH_LANG, value, display, rlang) && ok;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// .... do we care?
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkPropertyValue(List<ValidationMessage> errors, Element cs, NodeStack stack, Element property, Map<String, PropertyDef> properties) {
|
||||||
|
boolean ok = true;
|
||||||
|
|
||||||
|
String code = property.getNamedChildValue("code");
|
||||||
|
Element value = property.getNamedChild("value");
|
||||||
|
if (code != null) {
|
||||||
|
PropertyDef defn = properties.get(code);
|
||||||
|
if (rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), defn != null, I18nConstants.CODESYSTEM_PROPERTY_UNDEFINED, code) &&
|
||||||
|
rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), value != null, I18nConstants.CODESYSTEM_PROPERTY_NO_VALUE, code) &&
|
||||||
|
rule(errors, "2024-03-06", IssueType.BUSINESSRULE, cs.line(), cs.col(), stack.getLiteralPath(), value.fhirType().equals(defn.type), I18nConstants.CODESYSTEM_PROPERTY_WRONG_TYPE, code, value.fhirType(), defn.type)) {
|
||||||
|
// nothing?
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkShareableCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack) {
|
private boolean checkShareableCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack) {
|
||||||
|
|
Loading…
Reference in New Issue