* Improve terminology validation error messages

* add additional validation on profiles around types (for logical models)
This commit is contained in:
Grahame Grieve 2021-03-03 13:30:58 +11:00
parent a25f17a916
commit cd7a8d39e7
4 changed files with 58 additions and 22 deletions

View File

@ -1 +1,6 @@
* adding session ids to validator service
* fix R5 --> R4 conversion for ConceptMap equivalence default value
* fix issue with snapshot generation for logical models (CCDA)
* Define binding method extension
* Improve terminology validation error messages
* add additional validation on profiles around types (for logical models)

View File

@ -361,6 +361,8 @@ public class I18nConstants {
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 SD_VALUE_TYPE_IILEGAL = "SD_VALUE_TYPE_IILEGAL";
public static final String SD_NO_TYPES = "SD_NO_TYPES";
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";
@ -386,9 +388,9 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_CODE_VALUESETMAX = "Terminology_TX_Code_ValueSetMax";
public static final String TERMINOLOGY_TX_CODE_VALUESET_EXT = "Terminology_TX_Code_ValueSet_Ext";
public static final String TERMINOLOGY_TX_CODING_COUNT = "Terminology_TX_Coding_Count";
public static final String TERMINOLOGY_TX_CONFIRM_1 = "Terminology_TX_Confirm_1";
public static final String TERMINOLOGY_TX_CONFIRM_2 = "Terminology_TX_Confirm_2";
public static final String TERMINOLOGY_TX_CONFIRM_3 = "Terminology_TX_Confirm_3";
public static final String TERMINOLOGY_TX_CONFIRM_1_CC = "Terminology_TX_Confirm_1_CC";
public static final String TERMINOLOGY_TX_CONFIRM_2_CC = "Terminology_TX_Confirm_2_CC";
public static final String TERMINOLOGY_TX_CONFIRM_3_CC = "Terminology_TX_Confirm_3_CC";
public static final String TERMINOLOGY_TX_CONFIRM_4a = "Terminology_TX_Confirm_4a";
public static final String TERMINOLOGY_TX_CONFIRM_4b = "Terminology_TX_Confirm_4b";
public static final String TERMINOLOGY_TX_CONFIRM_5 = "Terminology_TX_Confirm_5";
@ -398,7 +400,7 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_ERROR_CODEABLECONCEPT_MAX = "Terminology_TX_Error_CodeableConcept_Max";
public static final String TERMINOLOGY_TX_ERROR_CODING1 = "Terminology_TX_Error_Coding1";
public static final String TERMINOLOGY_TX_ERROR_CODING2 = "Terminology_TX_Error_Coding2";
public static final String TERMINOLOGY_TX_NOVALID_1 = "Terminology_TX_NoValid_1";
public static final String TERMINOLOGY_TX_NOVALID_1_CC = "Terminology_TX_NoValid_1_CC";
public static final String TERMINOLOGY_TX_NOVALID_10 = "Terminology_TX_NoValid_10";
public static final String TERMINOLOGY_TX_NOVALID_11 = "Terminology_TX_NoValid_11";
public static final String TERMINOLOGY_TX_NOVALID_12 = "Terminology_TX_NoValid_12";
@ -408,8 +410,8 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_NOVALID_16 = "Terminology_TX_NoValid_16";
public static final String TERMINOLOGY_TX_NOVALID_17 = "Terminology_TX_NoValid_17";
public static final String TERMINOLOGY_TX_NOVALID_18 = "Terminology_TX_NoValid_18";
public static final String TERMINOLOGY_TX_NOVALID_2 = "Terminology_TX_NoValid_2";
public static final String TERMINOLOGY_TX_NOVALID_3 = "Terminology_TX_NoValid_3";
public static final String TERMINOLOGY_TX_NOVALID_2_CC = "Terminology_TX_NoValid_2_CC";
public static final String TERMINOLOGY_TX_NOVALID_3_CC = "Terminology_TX_NoValid_3_CC";
public static final String TERMINOLOGY_TX_NOVALID_4 = "Terminology_TX_NoValid_4";
public static final String TERMINOLOGY_TX_NOVALID_5 = "Terminology_TX_NoValid_5";
public static final String TERMINOLOGY_TX_NOVALID_6 = "Terminology_TX_NoValid_6";

View File

@ -1023,28 +1023,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
} else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
}
}
} else {
if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.getStrength() == BindingStrength.REQUIRED) {
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
}
}
}
@ -1137,28 +1137,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
bindingsOk = false;
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
else if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString());
}
}
} else {
if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack);
if (!noExtensibleWarnings)
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc));
}
}
}
@ -2220,6 +2220,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
* 2. This code doesn't actually decode, which is much easier on memory use for big payloads
*/
private boolean isValidBase64(String theEncoded) {
if (theEncoded == null) {
return false;
}
int charCount = 0;
boolean ok = true;
for (int i = 0; i < theEncoded.length(); i++) {
@ -4678,8 +4681,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ed.getMin() > 0) {
if (problematicPaths.contains(ed.getPath()))
hint(errors, IssueType.NOTSUPPORTED, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_NOCHECKMIN, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()));
else
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), count >= ed.getMin(), I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
else {
if (count < ed.getMin()) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_MINIMUM, profile.getUrl(), ed.getPath(), ed.getId(), ed.getSliceName(),ed.getLabel(), stack.getLiteralPath(), Integer.toString(ed.getMin()), Integer.toString(count));
}
}
}
if (ed.hasMax() && !ed.getMax().equals("*")) {
if (problematicPaths.contains(ed.getPath()))

View File

@ -146,6 +146,23 @@ public class StructureDefinitionValidator extends BaseValidator {
// String bt = boundType(typeCodes);
// hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
}
// in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
if (snapshot && element.getIdBase().contains(".")) {
if (rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty(), I18nConstants.SD_NO_TYPES, element.getIdBase())) {
Element v = element.getNamedChild("defaultValue");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes);
}
v = element.getNamedChild("fixed");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes);
}
v = element.getNamedChild("pattern");
if (v != null) {
rule(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes);
}
}
}
}
private String boundType(Set<String> typeCodes) {
@ -166,6 +183,12 @@ public class StructureDefinitionValidator extends BaseValidator {
if (Utilities.existsInList(tc, "string", "uri", "CodeableConcept", "Quantity", "CodeableReference")) {
return tc;
}
StructureDefinition sd = context.fetchTypeDefinition(tc);
if (sd != null) {
if (sd.hasExtension(ToolingExtensions.EXT_BINDING_METHOD)) {
return tc;
}
}
}
return null;
}