add value set qa checking
This commit is contained in:
parent
e324047735
commit
8980df2364
|
@ -922,6 +922,8 @@ public class I18nConstants {
|
||||||
public static final String TERMINOLOGY_TX_HINT = "TERMINOLOGY_TX_HINT";
|
public static final String TERMINOLOGY_TX_HINT = "TERMINOLOGY_TX_HINT";
|
||||||
public static final String TERMINOLOGY_TX_WARNING = "TERMINOLOGY_TX_WARNING";
|
public static final String TERMINOLOGY_TX_WARNING = "TERMINOLOGY_TX_WARNING";
|
||||||
public static final String SD_ED_TYPE_PROFILE_WRONG_TYPE = "SD_ED_TYPE_PROFILE_WRONG_TYPE";
|
public static final String SD_ED_TYPE_PROFILE_WRONG_TYPE = "SD_ED_TYPE_PROFILE_WRONG_TYPE";
|
||||||
|
public static final String VALUESET_CONCEPT_DISPLAY_PRESENCE_MIXED = "VALUESET_CONCEPT_DISPLAY_PRESENCE_MIXED";
|
||||||
|
public static final String VALUESET_CONCEPT_DISPLAY_SCT_TAG_MIXED = "VALUESET_CONCEPT_DISPLAY_SCT_TAG_MIXED";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -977,3 +977,5 @@ TERMINOLOGY_TX_HINT = {1}
|
||||||
TERMINOLOGY_TX_WARNING = {1}
|
TERMINOLOGY_TX_WARNING = {1}
|
||||||
SD_ED_TYPE_WRONG_TYPE_one = The element has a type {0} which is different to the type {1} on the base profile {2}
|
SD_ED_TYPE_WRONG_TYPE_one = The element has a type {0} which is different to the type {1} on the base profile {2}
|
||||||
SD_ED_TYPE_WRONG_TYPE_other = The element has a type {0} which is not in the types {1} on the base profile {2}
|
SD_ED_TYPE_WRONG_TYPE_other = The element has a type {0} which is not in the types {1} on the base profile {2}
|
||||||
|
VALUESET_CONCEPT_DISPLAY_PRESENCE_MIXED = This include has some concepts with displays and some without - check that this is what is intended
|
||||||
|
VALUESET_CONCEPT_DISPLAY_SCT_TAG_MIXED = This SNOMED-CT based include has some concepts with semantic tags (FSN terms) and some without (preferred terms) - check that this is what is intended
|
||||||
|
|
|
@ -22,10 +22,79 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||||
import org.hl7.fhir.validation.BaseValidator;
|
import org.hl7.fhir.validation.BaseValidator;
|
||||||
import org.hl7.fhir.validation.TimeTracker;
|
import org.hl7.fhir.validation.TimeTracker;
|
||||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||||
|
import org.hl7.fhir.validation.instance.type.ValueSetValidator.SystemLevelValidator;
|
||||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||||
|
|
||||||
public class ValueSetValidator extends BaseValidator {
|
public class ValueSetValidator extends BaseValidator {
|
||||||
|
|
||||||
|
public class SystemLevelValidator {
|
||||||
|
protected List<ValidationMessage> errors;
|
||||||
|
protected Element inc;
|
||||||
|
protected NodeStack stack;
|
||||||
|
|
||||||
|
private boolean noDisplay = false;
|
||||||
|
private boolean hasDisplay = false;
|
||||||
|
protected SystemLevelValidator(List<ValidationMessage> errors, Element inc, NodeStack stack) {
|
||||||
|
super();
|
||||||
|
this.errors = errors;
|
||||||
|
this.inc = inc;
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkConcept(String code, String display) {
|
||||||
|
if (Utilities.noString(display)) {
|
||||||
|
noDisplay = true;
|
||||||
|
} else {
|
||||||
|
hasDisplay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
hint(errors, "2023-07-21", IssueType.BUSINESSRULE, inc.line(), inc.col(), stack.getLiteralPath(), !(noDisplay && hasDisplay), I18nConstants.VALUESET_CONCEPT_DISPLAY_PRESENCE_MIXED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SnomedCTValidator extends SystemLevelValidator {
|
||||||
|
private boolean noTag = false;
|
||||||
|
private boolean hasTag = false;
|
||||||
|
|
||||||
|
protected SnomedCTValidator(List<ValidationMessage> errors, Element inc, NodeStack stack) {
|
||||||
|
super(errors, inc, stack);
|
||||||
|
}
|
||||||
|
public void checkConcept(String code, String display) {
|
||||||
|
super.checkConcept(code, display);
|
||||||
|
if (!Utilities.noString(display)) {
|
||||||
|
boolean tagged = display.endsWith(")") && display.indexOf("(") > display.length() - 20;
|
||||||
|
if (tagged) {
|
||||||
|
hasTag = true;
|
||||||
|
} else {
|
||||||
|
noTag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void finish() {
|
||||||
|
hint(errors, "2023-07-21", IssueType.BUSINESSRULE, inc.line(), inc.col(), stack.getLiteralPath(), !(noTag && hasTag), I18nConstants.VALUESET_CONCEPT_DISPLAY_SCT_TAG_MIXED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GeneralValidator extends SystemLevelValidator {
|
||||||
|
|
||||||
|
protected GeneralValidator(List<ValidationMessage> errors, Element inc, NodeStack stack) {
|
||||||
|
super(errors, inc, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private SystemLevelValidator getSystemValidator(String system, List<ValidationMessage> errors, Element inc, NodeStack stack) {
|
||||||
|
if (system == null) {
|
||||||
|
return new GeneralValidator(errors, inc, stack);
|
||||||
|
}
|
||||||
|
switch (system) {
|
||||||
|
case "http://snomed.info/sct" :return new SnomedCTValidator(errors, inc, stack);
|
||||||
|
default: return new GeneralValidator(errors, inc, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class VSCodingValidationRequest extends CodingValidationRequest {
|
public class VSCodingValidationRequest extends CodingValidationRequest {
|
||||||
|
|
||||||
private NodeStack stack;
|
private NodeStack stack;
|
||||||
|
@ -139,6 +208,8 @@ public class ValueSetValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
List<Element> concepts = include.getChildrenByName("concept");
|
List<Element> concepts = include.getChildrenByName("concept");
|
||||||
List<Element> filters = include.getChildrenByName("filter");
|
List<Element> filters = include.getChildrenByName("filter");
|
||||||
|
|
||||||
|
SystemLevelValidator slv = getSystemValidator(system, errors, include, stack);
|
||||||
if (!Utilities.noString(system)) {
|
if (!Utilities.noString(system)) {
|
||||||
boolean systemOk = true;
|
boolean systemOk = true;
|
||||||
int cc = 0;
|
int cc = 0;
|
||||||
|
@ -147,10 +218,10 @@ public class ValueSetValidator extends BaseValidator {
|
||||||
for (Element concept : concepts) {
|
for (Element concept : concepts) {
|
||||||
// we treat the first differently because we want to know if tbe system is worth validating. if it is, then we batch the rest
|
// we treat the first differently because we want to know if tbe system is worth validating. if it is, then we batch the rest
|
||||||
if (first) {
|
if (first) {
|
||||||
systemOk = validateValueSetIncludeConcept(errors, concept, stack, stack.push(concept, cc, null, null), system, version);
|
systemOk = validateValueSetIncludeConcept(errors, concept, stack, stack.push(concept, cc, null, null), system, version, slv);
|
||||||
first = false;
|
first = false;
|
||||||
} else if (systemOk) {
|
} else if (systemOk) {
|
||||||
batch.add(prepareValidateValueSetIncludeConcept(errors, concept, stack.push(concept, cc, null, null), system, version));
|
batch.add(prepareValidateValueSetIncludeConcept(errors, concept, stack.push(concept, cc, null, null), system, version, slv));
|
||||||
}
|
}
|
||||||
cc++;
|
cc++;
|
||||||
}
|
}
|
||||||
|
@ -180,19 +251,24 @@ public class ValueSetValidator extends BaseValidator {
|
||||||
|
|
||||||
int cf = 0;
|
int cf = 0;
|
||||||
for (Element filter : filters) {
|
for (Element filter : filters) {
|
||||||
if (systemOk && !validateValueSetIncludeFilter(errors, include, stack.push(filter, cf, null, null), system, version)) {
|
if (systemOk && !validateValueSetIncludeFilter(errors, include, stack.push(filter, cf, null, null), system, version, slv)) {
|
||||||
systemOk = false;
|
systemOk = false;
|
||||||
}
|
}
|
||||||
cf++;
|
cf++;
|
||||||
}
|
}
|
||||||
|
slv.finish();
|
||||||
} else {
|
} else {
|
||||||
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), filters.size() == 0 && concepts.size() == 0, I18nConstants.VALUESET_NO_SYSTEM_WARNING);
|
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), filters.size() == 0 && concepts.size() == 0, I18nConstants.VALUESET_NO_SYSTEM_WARNING);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateValueSetIncludeConcept(List<ValidationMessage> errors, Element concept, NodeStack stackInc, NodeStack stack, String system, String version) {
|
|
||||||
|
private boolean validateValueSetIncludeConcept(List<ValidationMessage> errors, Element concept, NodeStack stackInc, NodeStack stack, String system, String version, SystemLevelValidator slv) {
|
||||||
String code = concept.getChildValue("code");
|
String code = concept.getChildValue("code");
|
||||||
|
String display = concept.getChildValue("display");
|
||||||
|
slv.checkConcept(code, display);
|
||||||
|
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
ValidationResult vv = context.validateCode(ValidationOptions.defaults(), new Coding(system, code, null), null);
|
ValidationResult vv = context.validateCode(ValidationOptions.defaults(), new Coding(system, code, null), null);
|
||||||
if (vv.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
|
if (vv.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
|
||||||
|
@ -229,8 +305,11 @@ public class ValueSetValidator extends BaseValidator {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VSCodingValidationRequest prepareValidateValueSetIncludeConcept(List<ValidationMessage> errors, Element concept, NodeStack stack, String system, String version) {
|
private VSCodingValidationRequest prepareValidateValueSetIncludeConcept(List<ValidationMessage> errors, Element concept, NodeStack stack, String system, String version, SystemLevelValidator slv) {
|
||||||
String code = concept.getChildValue("code");
|
String code = concept.getChildValue("code");
|
||||||
|
String display = concept.getChildValue("display");
|
||||||
|
slv.checkConcept(code, display);
|
||||||
|
|
||||||
Coding c = new Coding(system, code, null);
|
Coding c = new Coding(system, code, null);
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
c.setVersion(version);
|
c.setVersion(version);
|
||||||
|
@ -238,7 +317,11 @@ public class ValueSetValidator extends BaseValidator {
|
||||||
return new VSCodingValidationRequest(stack, c);
|
return new VSCodingValidationRequest(stack, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateValueSetIncludeFilter(List<ValidationMessage> errors, Element include, NodeStack push, String system, String version) {
|
private boolean validateValueSetIncludeFilter(List<ValidationMessage> errors, Element filter, NodeStack push, String system, String version, SystemLevelValidator slv) {
|
||||||
|
//
|
||||||
|
// String display = concept.getChildValue("display");
|
||||||
|
// slv.checkConcept(code, display);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue