Fix bug validating mime types without terminology serverBase (warning, not error)
Performance improvements in JSON metadata based parser Add first round of supplement validation improve error message on profile validation fail fix NPE validating some slices fix bug validating canonicals as part of choice data types Adds special support for http://hl7.org/fhirpath/System.* types fix bug matching slices in contained resources that have references to #
This commit is contained in:
parent
2413ec1dbb
commit
ef3b8c1f0a
|
@ -750,7 +750,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
// 3rd pass: hit the server
|
// 3rd pass: hit the server
|
||||||
for (CodingValidationRequest t : codes) {
|
for (CodingValidationRequest t : codes) {
|
||||||
t.setCacheToken(txCache != null ? txCache.generateValidationToken(options, t.getCoding(), vs) : null);
|
t.setCacheToken(txCache != null ? txCache.generateValidationToken(options, t.getCoding(), vs) : null);
|
||||||
codeSystemsUsed.add(t.getCoding().getSystem());
|
if (t.getCoding().hasSystem()) {
|
||||||
|
codeSystemsUsed.add(t.getCoding().getSystem());
|
||||||
|
}
|
||||||
if (txCache != null) {
|
if (txCache != null) {
|
||||||
t.setResult(txCache.getValidation(t.getCacheToken()));
|
t.setResult(txCache.getValidation(t.getCacheToken()));
|
||||||
}
|
}
|
||||||
|
@ -846,7 +848,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
options = ValidationOptions.defaults();
|
options = ValidationOptions.defaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
codeSystemsUsed.add(code.getSystem());
|
if (code.hasSystem()) {
|
||||||
|
codeSystemsUsed.add(code.getSystem());
|
||||||
|
}
|
||||||
CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null;
|
CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null;
|
||||||
ValidationResult res = null;
|
ValidationResult res = null;
|
||||||
if (txCache != null) {
|
if (txCache != null) {
|
||||||
|
@ -922,7 +926,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
for (Coding c : code.getCoding()) {
|
for (Coding c : code.getCoding()) {
|
||||||
codeSystemsUsed.add(c.getSystem());
|
if (c.hasSystem()) {
|
||||||
|
codeSystemsUsed.add(c.getSystem());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.isUseClient()) {
|
if (options.isUseClient()) {
|
||||||
|
@ -1134,6 +1140,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
return noTerminologyServer;
|
return noTerminologyServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNoTerminologyServer(boolean noTerminologyServer) {
|
||||||
|
this.noTerminologyServer = noTerminologyServer;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,15 +76,19 @@ public class JsonParser extends ParserBase {
|
||||||
private Map<JsonElement, LocationData> map;
|
private Map<JsonElement, LocationData> map;
|
||||||
private boolean allowComments;
|
private boolean allowComments;
|
||||||
|
|
||||||
private FHIRPathEngine fpe;
|
|
||||||
private ProfileUtilities profileUtilities;
|
private ProfileUtilities profileUtilities;
|
||||||
|
|
||||||
public JsonParser(IWorkerContext context) {
|
public JsonParser(IWorkerContext context, ProfileUtilities utilities) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
this.fpe = new FHIRPathEngine(this.context);
|
this.profileUtilities = utilities;
|
||||||
this.profileUtilities = new ProfileUtilities(this.context, null, null, this.fpe);
|
}
|
||||||
}
|
|
||||||
|
public JsonParser(IWorkerContext context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
this.profileUtilities = new ProfileUtilities(this.context, null, null, new FHIRPathEngine(context));
|
||||||
|
}
|
||||||
|
|
||||||
public Element parse(String source, String type) throws Exception {
|
public Element parse(String source, String type) throws Exception {
|
||||||
JsonObject obj = (JsonObject) new com.google.gson.JsonParser().parse(source);
|
JsonObject obj = (JsonObject) new com.google.gson.JsonParser().parse(source);
|
||||||
|
|
|
@ -152,6 +152,9 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
|
||||||
throw new FHIRException(warningMessage);
|
throw new FHIRException(warningMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cs != null && cs.hasSupplements()) {
|
||||||
|
return new ValidationResult(IssueSeverity.ERROR, context.formatMessage(I18nConstants.CODESYSTEM_CS_NO_SUPPLEMENT, cs.getUrl()));
|
||||||
|
}
|
||||||
if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) {
|
if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) {
|
||||||
warningMessage = "Resolved system "+system+", but the definition is not complete";
|
warningMessage = "Resolved system "+system+", but the definition is not complete";
|
||||||
if (!inExpansion && cs.getContent() != CodeSystemContentMode.FRAGMENT) { // we're going to give it a go if it's a fragment
|
if (!inExpansion && cs.getContent() != CodeSystemContentMode.FRAGMENT) { // we're going to give it a go if it's a fragment
|
||||||
|
|
|
@ -304,7 +304,6 @@ public class FHIRPathEngine {
|
||||||
public ValueSet resolveValueSet(Object appContext, String url);
|
public ValueSet resolveValueSet(Object appContext, String url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param worker - used when validating paths (@check), and used doing value set membership when executing tests (once that's defined)
|
* @param worker - used when validating paths (@check), and used doing value set membership when executing tests (once that's defined)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,6 +50,9 @@ public class I18nConstants {
|
||||||
public static final String CODESYSTEM_CS_VS_INVALID = "CodeSystem_CS_VS_Invalid";
|
public static final String CODESYSTEM_CS_VS_INVALID = "CodeSystem_CS_VS_Invalid";
|
||||||
public static final String CODESYSTEM_CS_VS_EXP_MISMATCH = "CODESYSTEM_CS_VS_EXP_MISMATCH";
|
public static final String CODESYSTEM_CS_VS_EXP_MISMATCH = "CODESYSTEM_CS_VS_EXP_MISMATCH";
|
||||||
public static final String CODESYSTEM_CS_VS_WRONGSYSTEM = "CodeSystem_CS_VS_WrongSystem";
|
public static final String CODESYSTEM_CS_VS_WRONGSYSTEM = "CodeSystem_CS_VS_WrongSystem";
|
||||||
|
public static final String CODESYSTEM_CS_NO_SUPPLEMENT = "CODESYSTEM_CS_NO_SUPPLEMENT";
|
||||||
|
public static final String CODESYSTEM_CS_SUPP_CANT_CHECK = "CODESYSTEM_CS_SUPP_CANT_CHECK";
|
||||||
|
public static final String CODESYSTEM_CS_SUPP_INVALID_CODE = "CODESYSTEM_CS_SUPP_INVALID_CODE";
|
||||||
public static final String CODE_FOUND_IN_EXPANSION_HOWEVER_ = "Code_found_in_expansion_however_";
|
public static final String CODE_FOUND_IN_EXPANSION_HOWEVER_ = "Code_found_in_expansion_however_";
|
||||||
public static final String CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE = "Coding_has_no_system__cannot_validate";
|
public static final String CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE = "Coding_has_no_system__cannot_validate";
|
||||||
public static final String CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_ = "Contained_resource_does_not_appear_to_be_a_FHIR_resource_unknown_name_";
|
public static final String CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_ = "Contained_resource_does_not_appear_to_be_a_FHIR_resource_unknown_name_";
|
||||||
|
|
|
@ -7,12 +7,12 @@ package org.hl7.fhir.utilities.validation;
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
are permitted provided that the following conditions are met:
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
list of conditions and the following disclaimer.
|
list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
this list of conditions and the following disclaimer in the documentation
|
this list of conditions and the following disclaimer in the documentation
|
||||||
and/or other materials provided with the distribution.
|
and/or other materials provided with the distribution.
|
||||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||||
endorse or promote products derived from this software without specific
|
endorse or promote products derived from this software without specific
|
||||||
prior written permission.
|
prior written permission.
|
||||||
|
|
||||||
|
@ -127,6 +127,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case ERROR: return "error";
|
case ERROR: return "error";
|
||||||
case WARNING: return "warning";
|
case WARNING: return "warning";
|
||||||
case INFORMATION: return "information";
|
case INFORMATION: return "information";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,6 +137,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case ERROR: return "http://hl7.org/fhir/issue-severity";
|
case ERROR: return "http://hl7.org/fhir/issue-severity";
|
||||||
case WARNING: return "http://hl7.org/fhir/issue-severity";
|
case WARNING: return "http://hl7.org/fhir/issue-severity";
|
||||||
case INFORMATION: return "http://hl7.org/fhir/issue-severity";
|
case INFORMATION: return "http://hl7.org/fhir/issue-severity";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,6 +147,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case ERROR: return "The issue is sufficiently important to cause the action to fail.";
|
case ERROR: return "The issue is sufficiently important to cause the action to fail.";
|
||||||
case WARNING: return "The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired.";
|
case WARNING: return "The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired.";
|
||||||
case INFORMATION: return "The issue has no relation to the degree of success of the action.";
|
case INFORMATION: return "The issue has no relation to the degree of success of the action.";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +157,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case ERROR: return "Error";
|
case ERROR: return "Error";
|
||||||
case WARNING: return "Warning";
|
case WARNING: return "Warning";
|
||||||
case INFORMATION: return "Information";
|
case INFORMATION: return "Information";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,6 +384,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case TIMEOUT: return "timeout";
|
case TIMEOUT: return "timeout";
|
||||||
case THROTTLED: return "throttled";
|
case THROTTLED: return "throttled";
|
||||||
case INFORMATIONAL: return "informational";
|
case INFORMATIONAL: return "informational";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,6 +419,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case TIMEOUT: return "http://hl7.org/fhir/issue-type";
|
case TIMEOUT: return "http://hl7.org/fhir/issue-type";
|
||||||
case THROTTLED: return "http://hl7.org/fhir/issue-type";
|
case THROTTLED: return "http://hl7.org/fhir/issue-type";
|
||||||
case INFORMATIONAL: return "http://hl7.org/fhir/issue-type";
|
case INFORMATIONAL: return "http://hl7.org/fhir/issue-type";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,6 +454,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case TIMEOUT: return "An internal timeout has occurred.";
|
case TIMEOUT: return "An internal timeout has occurred.";
|
||||||
case THROTTLED: return "The system is not prepared to handle this request due to load management.";
|
case THROTTLED: return "The system is not prepared to handle this request due to load management.";
|
||||||
case INFORMATIONAL: return "A message unrelated to the processing success of the completed operation (examples of the latter include things like reminders of password expiry, system maintenance times, etc.).";
|
case INFORMATIONAL: return "A message unrelated to the processing success of the completed operation (examples of the latter include things like reminders of password expiry, system maintenance times, etc.).";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,6 +489,7 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
|
||||||
case TIMEOUT: return "Timeout";
|
case TIMEOUT: return "Timeout";
|
||||||
case THROTTLED: return "Throttled";
|
case THROTTLED: return "Throttled";
|
||||||
case INFORMATIONAL: return "Informational Note";
|
case INFORMATIONAL: return "Informational Note";
|
||||||
|
case NULL: return null;
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,8 +106,8 @@ Questionnaire_Q_EnableWhen_Self = Target for this question enableWhen can''t ref
|
||||||
Reference_REF_Aggregation = Reference is {0} which isn''t supported by the specified aggregation mode(s) for the reference ({1})
|
Reference_REF_Aggregation = Reference is {0} which isn''t supported by the specified aggregation mode(s) for the reference ({1})
|
||||||
Reference_REF_BadTargetType = Invalid Resource target type. Found {0}, but expected one of ({1})
|
Reference_REF_BadTargetType = Invalid Resource target type. Found {0}, but expected one of ({1})
|
||||||
Reference_REF_BadTargetType2 = The type ''{0}'' implied by the reference URL {1} is not a valid Target for this element (must be one of {2})
|
Reference_REF_BadTargetType2 = The type ''{0}'' implied by the reference URL {1} is not a valid Target for this element (must be one of {2})
|
||||||
Reference_REF_CantMatchChoice = Unable to find matching profile for {0} among choices: {1}
|
Reference_REF_CantMatchChoice = Unable to find a match for profile {0} among choices: {1}
|
||||||
Reference_REF_CantMatchType = Unable to find matching profile for {0} (by type) among choices: {1}
|
Reference_REF_CantMatchType = Unable to find a match for profile {0} (by type) among choices: {1}
|
||||||
Reference_REF_CantResolve = Unable to resolve resource ''{0}''
|
Reference_REF_CantResolve = Unable to resolve resource ''{0}''
|
||||||
Reference_REF_CantResolveProfile = Unable to resolve the profile reference ''{0}''
|
Reference_REF_CantResolveProfile = Unable to resolve the profile reference ''{0}''
|
||||||
Reference_REF_Format1 = Relative URLs must be of the format [ResourceName]/[id], or a search URL is allowed ([type]?parameters. Encountered {0})
|
Reference_REF_Format1 = Relative URLs must be of the format [ResourceName]/[id], or a search URL is allowed ([type]?parameters. Encountered {0})
|
||||||
|
@ -217,7 +217,7 @@ Validation_VAL_Profile_NoCheckMax = {2}: Unable to check max allowed ({1}) due t
|
||||||
Validation_VAL_Profile_NoCheckMin = {2}: Unable to check minimum required ({1}) due to lack of slicing validation (from {0})
|
Validation_VAL_Profile_NoCheckMin = {2}: Unable to check minimum required ({1}) due to lack of slicing validation (from {0})
|
||||||
Validation_VAL_Profile_MultipleMatches = Found multiple matching profiles among choices: {0}
|
Validation_VAL_Profile_MultipleMatches = Found multiple matching profiles among choices: {0}
|
||||||
Validation_VAL_Profile_NoDefinition = No definition found for resource type ''{0}''
|
Validation_VAL_Profile_NoDefinition = No definition found for resource type ''{0}''
|
||||||
Validation_VAL_Profile_NoMatch = Unable to find matching profile among choices: {0}
|
Validation_VAL_Profile_NoMatch = Unable to find a match for the specified profile among choices: {0}
|
||||||
Validation_VAL_Profile_NoSnapshot = StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided
|
Validation_VAL_Profile_NoSnapshot = StructureDefinition has no snapshot - validation is against the snapshot, so it must be provided
|
||||||
Validation_VAL_Profile_NoType = The type of element {0} is not known, which is illegal. Valid types at this point are {1}
|
Validation_VAL_Profile_NoType = The type of element {0} is not known, which is illegal. Valid types at this point are {1}
|
||||||
Validation_VAL_Profile_NotAllowed = This element is not allowed by the profile {0}
|
Validation_VAL_Profile_NotAllowed = This element is not allowed by the profile {0}
|
||||||
|
@ -636,3 +636,6 @@ DISCRIMINATOR_BAD_PATH = Error processing path expression for disciminator: {0}
|
||||||
SLICING_CANNOT_BE_EVALUATED = Slicing cannot be evaluated: {0}
|
SLICING_CANNOT_BE_EVALUATED = Slicing cannot be evaluated: {0}
|
||||||
TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE = Canonical URL ''{0}'' does not resolve
|
TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE = Canonical URL ''{0}'' does not resolve
|
||||||
TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = Canonical URL ''{0}'' refers to a resource that has the wrong type. Found {1} expecting one of {2}
|
TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = Canonical URL ''{0}'' refers to a resource that has the wrong type. Found {1} expecting one of {2}
|
||||||
|
CODESYSTEM_CS_NO_SUPPLEMENT = CodeSystem {0} is a supplement, so can't be used as a value in Coding.system
|
||||||
|
CODESYSTEM_CS_SUPP_CANT_CHECK = CodeSystem {0} cannot be found, so can't check if concepts are valid
|
||||||
|
CODESYSTEM_CS_SUPP_INVALID_CODE = The code ''{1}'' is not declared in the base CodeSystem {0} so is not valid in the supplement
|
||||||
|
|
|
@ -834,6 +834,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
|
||||||
context.setTlogging(false);
|
context.setTlogging(false);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
context.setCanRunWithoutTerminology(true);
|
context.setCanRunWithoutTerminology(true);
|
||||||
|
context.setNoTerminologyServer(true);
|
||||||
return "n/a: No Terminology Server";
|
return "n/a: No Terminology Server";
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -129,10 +129,10 @@ public class Params {
|
||||||
cliContext.getBundleValidationRules().add(new BundleValidationRule(r, p));
|
cliContext.getBundleValidationRules().add(new BundleValidationRule(r, p));
|
||||||
} else if (args[i].equals(QUESTIONNAIRE)) {
|
} else if (args[i].equals(QUESTIONNAIRE)) {
|
||||||
if (i + 1 == args.length)
|
if (i + 1 == args.length)
|
||||||
throw new Error("Specified -questionnaire without indicating questionnaire file");
|
throw new Error("Specified -questionnaire without indicating questionnaire mode");
|
||||||
else {
|
else {
|
||||||
String q = args[++i];
|
String q = args[++i];
|
||||||
cliContext.setQuestionnaireMode(QuestionnaireMode.valueOf(q));
|
cliContext.setQuestionnaireMode(QuestionnaireMode.fromCode(q));
|
||||||
}
|
}
|
||||||
} else if (args[i].equals(NATIVE)) {
|
} else if (args[i].equals(NATIVE)) {
|
||||||
cliContext.setDoNative(true);
|
cliContext.setDoNative(true);
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class ProfileLoader {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(src + "?nocache=" + System.currentTimeMillis());
|
URL url = new URL(src + "?nocache=" + System.currentTimeMillis());
|
||||||
URLConnection c = url.openConnection();
|
URLConnection c = url.openConnection();
|
||||||
|
|
||||||
return IOUtils.toByteArray(c.getInputStream());
|
return IOUtils.toByteArray(c.getInputStream());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FHIRException("Unable to find definitions at URL '" + src + "': " + e.getMessage(), e);
|
throw new FHIRException("Unable to find definitions at URL '" + src + "': " + e.getMessage(), e);
|
||||||
|
|
|
@ -660,7 +660,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List<ValidationMessage> errors, JsonObject object, List<StructureDefinition> profiles) throws FHIRException {
|
public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List<ValidationMessage> errors, JsonObject object, List<StructureDefinition> profiles) throws FHIRException {
|
||||||
JsonParser parser = new JsonParser(context);
|
JsonParser parser = new JsonParser(context, new ProfileUtilities(context, null, null, fpe));
|
||||||
parser.setupValidation(ValidationPolicy.EVERYTHING, errors);
|
parser.setupValidation(ValidationPolicy.EVERYTHING, errors);
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
Element e = parser.parse(object);
|
Element e = parser.parse(object);
|
||||||
|
@ -2158,6 +2158,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (tr.getTargetProfile().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2400,7 +2403,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
|
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
|
||||||
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
|
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"), value, stack);
|
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), value, stack);
|
||||||
else if (!noExtensibleWarnings)
|
else if (!noExtensibleWarnings && !isOkExtension(value, vs))
|
||||||
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage()));
|
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage()));
|
||||||
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
|
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
|
||||||
if (baseOnly) {
|
if (baseOnly) {
|
||||||
|
@ -2413,6 +2416,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, !type.equals("code"), I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE2);
|
hint(errors, IssueType.CODEINVALID, element.line(), element.col(), path, !type.equals("code"), I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOkExtension(String value, ValueSet vs) {
|
||||||
|
if ("http://hl7.org/fhir/ValueSet/defined-types".equals(vs.getUrl())) {
|
||||||
|
return value.startsWith("http://hl7.org/fhirpath/System.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void checkQuantity(List<ValidationMessage> errors, String path, Element focus, Quantity fixed, String fixedSource, boolean pattern) {
|
private void checkQuantity(List<ValidationMessage> errors, String path, Element focus, Quantity fixed, String fixedSource, boolean pattern) {
|
||||||
checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern);
|
checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern);
|
||||||
checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator"), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern);
|
checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator"), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern);
|
||||||
|
@ -3166,36 +3176,53 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
// really, there should only be one level for this (contained resources cannot contain
|
// really, there should only be one level for this (contained resources cannot contain
|
||||||
// contained resources), but we'll leave that to some other code to worry about
|
// contained resources), but we'll leave that to some other code to worry about
|
||||||
boolean wasContained = false;
|
boolean wasContained = false;
|
||||||
while (stack != null && stack.getElement() != null) {
|
NodeStack nstack = stack;
|
||||||
if (stack.getElement().getProperty().isResource()) {
|
while (nstack != null && nstack.getElement() != null) {
|
||||||
|
if (nstack.getElement().getProperty().isResource()) {
|
||||||
// ok, we'll try to find the contained reference
|
// ok, we'll try to find the contained reference
|
||||||
if (ref.equals("#") && stack.getElement().getSpecial() != SpecialElement.CONTAINED && wasContained) {
|
if (ref.equals("#") && nstack.getElement().getSpecial() != SpecialElement.CONTAINED && wasContained) {
|
||||||
ResolvedReference rr = new ResolvedReference();
|
ResolvedReference rr = new ResolvedReference();
|
||||||
rr.setResource(stack.getElement());
|
rr.setResource(nstack.getElement());
|
||||||
rr.setFocus(stack.getElement());
|
rr.setFocus(nstack.getElement());
|
||||||
rr.setExternal(false);
|
rr.setExternal(false);
|
||||||
rr.setStack(stack.push(stack.getElement(), -1, stack.getElement().getProperty().getDefinition(), stack.getElement().getProperty().getDefinition()));
|
rr.setStack(nstack.push(nstack.getElement(), -1, nstack.getElement().getProperty().getDefinition(), nstack.getElement().getProperty().getDefinition()));
|
||||||
rr.getStack().qualifyPath(".ofType("+stack.getElement().fhirType()+")");
|
rr.getStack().qualifyPath(".ofType("+nstack.getElement().fhirType()+")");
|
||||||
return rr;
|
return rr;
|
||||||
}
|
}
|
||||||
if (stack.getElement().getSpecial() == SpecialElement.CONTAINED) {
|
if (nstack.getElement().getSpecial() == SpecialElement.CONTAINED) {
|
||||||
wasContained = true;
|
wasContained = true;
|
||||||
}
|
}
|
||||||
IndexedElement res = getContainedById(stack.getElement(), ref.substring(1));
|
IndexedElement res = getContainedById(nstack.getElement(), ref.substring(1));
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
ResolvedReference rr = new ResolvedReference();
|
ResolvedReference rr = new ResolvedReference();
|
||||||
rr.setResource(stack.getElement());
|
rr.setResource(nstack.getElement());
|
||||||
rr.setFocus(res.getMatch());
|
rr.setFocus(res.getMatch());
|
||||||
rr.setExternal(false);
|
rr.setExternal(false);
|
||||||
rr.setStack(stack.push(res.getMatch(), res.getIndex(), res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
|
rr.setStack(nstack.push(res.getMatch(), res.getIndex(), res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
|
||||||
rr.getStack().qualifyPath(".ofType("+stack.getElement().fhirType()+")");
|
rr.getStack().qualifyPath(".ofType("+nstack.getElement().fhirType()+")");
|
||||||
return rr;
|
return rr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || stack.getElement().getSpecial() == SpecialElement.PARAMETER) {
|
if (nstack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY || nstack.getElement().getSpecial() == SpecialElement.PARAMETER) {
|
||||||
return null; // we don't try to resolve contained references across this boundary
|
return null; // we don't try to resolve contained references across this boundary
|
||||||
}
|
}
|
||||||
stack = stack.getParent();
|
nstack = nstack.getParent();
|
||||||
|
}
|
||||||
|
// try again, and work up the element parent list
|
||||||
|
if (ref.equals("#")) {
|
||||||
|
Element e = stack.getElement();
|
||||||
|
while (e != null) {
|
||||||
|
if (e.getProperty().isResource() && (e.getSpecial() != SpecialElement.CONTAINED)) {
|
||||||
|
ResolvedReference rr = new ResolvedReference();
|
||||||
|
rr.setResource(e);
|
||||||
|
rr.setFocus(e);
|
||||||
|
rr.setExternal(false);
|
||||||
|
rr.setStack(stack.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()));
|
||||||
|
rr.getStack().qualifyPath(".ofType("+e.fhirType()+")");
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
e = e.getParentForValidator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4007,7 +4034,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
} else if (element.getType().equals("CapabilityStatement")) {
|
} else if (element.getType().equals("CapabilityStatement")) {
|
||||||
validateCapabilityStatement(errors, element, stack);
|
validateCapabilityStatement(errors, element, stack);
|
||||||
} else if (element.getType().equals("CodeSystem")) {
|
} else if (element.getType().equals("CodeSystem")) {
|
||||||
new CodeSystemValidator(context, timeTracker, xverManager).validateCodeSystem(errors, element, stack);
|
new CodeSystemValidator(context, timeTracker, xverManager).validateCodeSystem(errors, element, stack, new ValidationOptions(stack.getWorkingLang()));
|
||||||
} else if (element.getType().equals("SearchParameter")) {
|
} else if (element.getType().equals("SearchParameter")) {
|
||||||
new SearchParameterValidator(context, timeTracker, fpe, xverManager).validateSearchParameter(errors, element, stack);
|
new SearchParameterValidator(context, timeTracker, fpe, xverManager).validateSearchParameter(errors, element, stack);
|
||||||
} else if (element.getType().equals("StructureDefinition")) {
|
} else if (element.getType().equals("StructureDefinition")) {
|
||||||
|
@ -4951,15 +4978,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
if (inv.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice") &&
|
if (inv.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice") &&
|
||||||
ToolingExtensions.readBooleanExtension(inv, "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice")) {
|
ToolingExtensions.readBooleanExtension(inv, "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice")) {
|
||||||
if (bpWarnings == BestPracticeWarningLevel.Hint)
|
if (bpWarnings == BestPracticeWarningLevel.Hint)
|
||||||
hint(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": " + inv.getHuman() + msg + " [" + n.toString() + "]");
|
hint(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": '" + inv.getHuman()+"' " + (Utilities.noString(msg) ? "failed" : msg));
|
||||||
else if (bpWarnings == BestPracticeWarningLevel.Warning)
|
else if (bpWarnings == BestPracticeWarningLevel.Warning)
|
||||||
warning(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": " + inv.getHuman() + msg + " [" + n.toString() + "]");
|
warning(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": '" + inv.getHuman()+"' " + (Utilities.noString(msg) ? "failed" : msg));
|
||||||
else if (bpWarnings == BestPracticeWarningLevel.Error)
|
else if (bpWarnings == BestPracticeWarningLevel.Error)
|
||||||
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": " + inv.getHuman() + msg + " [" + n.toString() + "]");
|
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": '" + inv.getHuman()+"' " + (Utilities.noString(msg) ? "failed" : msg));
|
||||||
} else if (inv.getSeverity() == ConstraintSeverity.ERROR) {
|
} else if (inv.getSeverity() == ConstraintSeverity.ERROR) {
|
||||||
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": " + inv.getHuman() + msg + " [" + n.toString() + "]");
|
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getKey() + ": '" + inv.getHuman()+"' " + (Utilities.noString(msg) ? "failed" : msg));
|
||||||
} else if (inv.getSeverity() == ConstraintSeverity.WARNING) {
|
} else if (inv.getSeverity() == ConstraintSeverity.WARNING) {
|
||||||
warning(errors, IssueType.INVARIANT, element.line(), element.line(), path, ok, inv.getKey() + ": " + inv.getHuman() + msg + " [" + n.toString() + "]");
|
warning(errors, IssueType.INVARIANT, element.line(), element.line(), path, ok, inv.getKey() + ": '" + inv.getHuman()+"' " + (Utilities.noString(msg) ? "failed" : msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r5.elementmodel.Element;
|
import org.hl7.fhir.r5.elementmodel.Element;
|
||||||
|
import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
@ -12,10 +13,13 @@ import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
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.ValidationMessage.Source;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
|
||||||
|
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.utils.NodeStack;
|
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
|
||||||
public class CodeSystemValidator extends BaseValidator {
|
public class CodeSystemValidator extends BaseValidator {
|
||||||
|
|
||||||
public CodeSystemValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager) {
|
public CodeSystemValidator(IWorkerContext context, TimeTracker timeTracker, XVerExtensionManager xverManager) {
|
||||||
|
@ -24,7 +28,7 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
this.timeTracker = timeTracker;
|
this.timeTracker = timeTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack) {
|
public void validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) {
|
||||||
String url = cs.getNamedChildValue("url");
|
String url = cs.getNamedChildValue("url");
|
||||||
String content = cs.getNamedChildValue("content");
|
String content = cs.getNamedChildValue("content");
|
||||||
|
|
||||||
|
@ -52,6 +56,31 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // todo... try getting the value set the other way...
|
} // todo... try getting the value set the other way...
|
||||||
|
|
||||||
|
String supp = cs.getNamedChildValue("supplements");
|
||||||
|
if (supp != null) {
|
||||||
|
if (context.supportsSystem(supp)) {
|
||||||
|
List<Element> concepts = cs.getChildrenByName("concept");
|
||||||
|
int ce = 0;
|
||||||
|
for (Element concept : concepts) {
|
||||||
|
validateSupplementConcept(errors, concept, stack.push(concept, ce, null, null), supp, options);
|
||||||
|
ce++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cs.hasChildren("concept")) {
|
||||||
|
warning(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_SUPP_CANT_CHECK, supp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSupplementConcept(List<ValidationMessage> errors, Element concept, NodeStack stack, String supp, ValidationOptions options) {
|
||||||
|
String code = concept.getChildValue("code");
|
||||||
|
if (!Utilities.noString(code)) {
|
||||||
|
org.hl7.fhir.r5.context.IWorkerContext.ValidationResult res = context.validateCode(options, supp, code, null);
|
||||||
|
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), res.isOk(), I18nConstants.CODESYSTEM_CS_SUPP_INVALID_CODE, supp, code);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countConcepts(Element cs) {
|
private int countConcepts(Element cs) {
|
||||||
|
|
|
@ -86,7 +86,9 @@ public class ValidatorHostContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sliceNotes(String url, List<ValidationMessage> record) {
|
public void sliceNotes(String url, List<ValidationMessage> record) {
|
||||||
|
if (sliceRecords != null) {
|
||||||
sliceRecords.put(url, record);
|
sliceRecords.put(url, record);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidatorHostContext forContained(Element element) {
|
public ValidatorHostContext forContained(Element element) {
|
||||||
|
|
Loading…
Reference in New Issue