extend policy advisor to control terminology validation + hack fixes for problems in R4B
This commit is contained in:
parent
93d266b363
commit
7f5a1d95cc
|
@ -54,7 +54,7 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader {
|
||||||
if (VersionUtilities.isR5Ver(npm.fhirVersion())) {
|
if (VersionUtilities.isR5Ver(npm.fhirVersion())) {
|
||||||
return new R5ToR5Loader(types, lkp.forNewPackage(npm));
|
return new R5ToR5Loader(types, lkp.forNewPackage(npm));
|
||||||
} else if (VersionUtilities.isR4Ver(npm.fhirVersion())) {
|
} else if (VersionUtilities.isR4Ver(npm.fhirVersion())) {
|
||||||
return new R4ToR5Loader(types, lkp.forNewPackage(npm));
|
return new R4ToR5Loader(types, lkp.forNewPackage(npm), npm.version());
|
||||||
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {
|
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {
|
||||||
return new R3ToR5Loader(types, lkp.forNewPackage(npm));
|
return new R3ToR5Loader(types, lkp.forNewPackage(npm));
|
||||||
} else if (VersionUtilities.isR2Ver(npm.fhirVersion())) {
|
} else if (VersionUtilities.isR2Ver(npm.fhirVersion())) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.hl7.fhir.convertors.loaders.loaderR5;
|
package org.hl7.fhir.convertors.loaders.loaderR5;
|
||||||
|
|
||||||
|
import org.apache.http.auth.AuthScheme;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2011+, HL7, Inc.
|
Copyright (c) 2011+, HL7, Inc.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
@ -36,12 +38,14 @@ import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.formats.JsonParser;
|
import org.hl7.fhir.r4.formats.JsonParser;
|
||||||
import org.hl7.fhir.r4.formats.XmlParser;
|
import org.hl7.fhir.r4.formats.XmlParser;
|
||||||
import org.hl7.fhir.r4.model.Resource;
|
import org.hl7.fhir.r4.model.Resource;
|
||||||
|
import org.hl7.fhir.r5.conformance.StructureDefinitionHacker;
|
||||||
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
||||||
import org.hl7.fhir.r5.model.*;
|
import org.hl7.fhir.r5.model.*;
|
||||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.r5.model.Bundle.BundleType;
|
import org.hl7.fhir.r5.model.Bundle.BundleType;
|
||||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||||
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -52,9 +56,11 @@ import java.util.UUID;
|
||||||
public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader {
|
public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader {
|
||||||
|
|
||||||
private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
|
private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
|
||||||
|
private String version;
|
||||||
|
|
||||||
public R4ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp) {
|
public R4ToR5Loader(String[] types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
|
||||||
super(types, lkp);
|
super(types, lkp);
|
||||||
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,6 +129,9 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
|
||||||
if (killPrimitives) {
|
if (killPrimitives) {
|
||||||
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
throw new FHIRException("Cannot kill primitives when using deferred loading");
|
||||||
}
|
}
|
||||||
|
if (r5 instanceof StructureDefinition && VersionUtilities.isR4BVer(version)) {
|
||||||
|
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
|
||||||
|
}
|
||||||
if (patchUrls) {
|
if (patchUrls) {
|
||||||
if (r5 instanceof StructureDefinition) {
|
if (r5 instanceof StructureDefinition) {
|
||||||
StructureDefinition sd = (StructureDefinition) r5;
|
StructureDefinition sd = (StructureDefinition) r5;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.hl7.fhir.r5.conformance;
|
||||||
|
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||||
|
import org.hl7.fhir.r5.model.Resource;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
|
|
||||||
|
public class StructureDefinitionHacker {
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
public StructureDefinitionHacker(String version) {
|
||||||
|
super();
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource fixSD(StructureDefinition sd) {
|
||||||
|
if (VersionUtilities.isR4BVer(version) && sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type")) {
|
||||||
|
// the definition of this one is wrong in R4B
|
||||||
|
return fixR4BFhirType(sd);
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource fixR4BFhirType(StructureDefinition sd) {
|
||||||
|
for (ElementDefinition ed : sd.getDifferential().getElement()) {
|
||||||
|
if (ed.getPath().equals("Extension.value[x]")) {
|
||||||
|
fixEDType(ed, "url", "uri");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
|
||||||
|
if (ed.getPath().equals("Extension.value[x]")) {
|
||||||
|
fixEDType(ed, "url", "uri");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fixEDType(ElementDefinition ed, String orig, String repl) {
|
||||||
|
for (TypeRefComponent t : ed.getType()) {
|
||||||
|
if (orig.equals(t.getCode())) {
|
||||||
|
t.setCode(repl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,15 @@
|
||||||
package org.hl7.fhir.r5.utils.validation;
|
package org.hl7.fhir.r5.utils.validation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hl7.fhir.r5.elementmodel.Element;
|
import org.hl7.fhir.r5.elementmodel.Element;
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||||
|
|
||||||
public interface IValidationPolicyAdvisor {
|
public interface IValidationPolicyAdvisor {
|
||||||
|
|
||||||
|
@ -38,4 +45,38 @@ public interface IValidationPolicyAdvisor {
|
||||||
String path,
|
String path,
|
||||||
String url);
|
String url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before validating a concept in an instance against the terminology sub-system
|
||||||
|
*
|
||||||
|
* There's two reasons to use this policy advisor feature:
|
||||||
|
* - save time by not calling the terminology server for validation that don't bring value to the context calling the validation
|
||||||
|
* - suppressing known issues from being listed as a problem
|
||||||
|
*
|
||||||
|
* Note that the terminology subsystem has two parts: a mini-terminology server running inside the
|
||||||
|
* validator, and then calling out to an external terminology service (usually tx.fhir.org, though you
|
||||||
|
* run your own local copy of this - see https://confluence.hl7.org/display/FHIR/Running+your+own+copy+of+tx.fhir.org).
|
||||||
|
* You can't tell which subsystem will handle the terminology validation directly from the content provided here which
|
||||||
|
* subsystem will be called - you'll haev to investigate based on your set up. (matters, since it makes a huge performance
|
||||||
|
* difference, though it also depends on caching, and the impact of caching is also not known at this point)
|
||||||
|
*
|
||||||
|
* @param validator
|
||||||
|
* @param appContext What was originally provided from the app for it's context
|
||||||
|
* @param stackPath The current path for the stack. Note that the because of cross-references and FHIRPath conformsTo() statements, the stack can wind through the content unpredictably.
|
||||||
|
* @param definition the definition being validated against (might be useful: ElementDefinition.base.path, ElementDefinition.type, ElementDefinition.binding
|
||||||
|
* @param structure The structure definition that contains the element definition being validated against (may be from the base spec, may be from a profile)
|
||||||
|
* @param kind The part of the binding being validated
|
||||||
|
* @param valueSet The value set for the binding part that's being validated
|
||||||
|
* @param systems A list of canonical URls (including versions if known) of the systems in the instance that's being validated. Note that if a plain code is being validated, then there'll be no known system when this is called (systems will be empty, not null)
|
||||||
|
* @return {@link CodedContentValidationPolicy}
|
||||||
|
*/
|
||||||
|
CodedContentValidationPolicy policyForCodedContent(IResourceValidator validator,
|
||||||
|
Object appContext,
|
||||||
|
String stackPath,
|
||||||
|
ElementDefinition definition,
|
||||||
|
StructureDefinition structure,
|
||||||
|
BindingKind kind,
|
||||||
|
ValueSet valueSet,
|
||||||
|
List<String> systems);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.hl7.fhir.r5.utils.validation.constants;
|
||||||
|
|
||||||
|
public enum BindingKind {
|
||||||
|
/**
|
||||||
|
* The primary binding e.g. ElementDefinition.binding.valueSet
|
||||||
|
*/
|
||||||
|
PRIMARY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The max value set
|
||||||
|
*/
|
||||||
|
MAX_VS;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.hl7.fhir.r5.utils.validation.constants;
|
||||||
|
|
||||||
|
public enum CodedContentValidationPolicy {
|
||||||
|
/**
|
||||||
|
* don't validate the code
|
||||||
|
*/
|
||||||
|
IGNORE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate the code against the underlying code systems
|
||||||
|
*/
|
||||||
|
CODE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate the code against the value set too.
|
||||||
|
* Note that this isn't much faster than just validating the code since
|
||||||
|
* the expensive part is hitting the terminology server (if necessary)
|
||||||
|
* and that has to be done for the code part too
|
||||||
|
*/
|
||||||
|
VALUESET //
|
||||||
|
}
|
|
@ -752,17 +752,12 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
Element.SpecialElement containingResourceType,
|
Element.SpecialElement containingResourceType,
|
||||||
String path,
|
String path,
|
||||||
String url) {
|
String url) {
|
||||||
Resource resource = context.fetchResource(StructureDefinition.class, url);
|
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||||
if (resource != null) {
|
}
|
||||||
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
|
||||||
}
|
@Override
|
||||||
if (!(url.contains("hl7.org") || url.contains("fhir.org"))) {
|
public CodedContentValidationPolicy policyForCodedContent(IResourceValidator validator, Object appContext, String stackPath, ElementDefinition definition, StructureDefinition structure, BindingKind kind, ValueSet valueSet, List<String> systems) {
|
||||||
return ContainedReferenceValidationPolicy.IGNORE;
|
return CodedContentValidationPolicy.VALUESET;
|
||||||
} else if (policyAdvisor != null) {
|
|
||||||
return policyAdvisor.policyForContained(validator, appContext, containerType, containerId, containingResourceType, path, url);
|
|
||||||
} else {
|
|
||||||
return ContainedReferenceValidationPolicy.CHECK_TYPE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -825,4 +820,5 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
public boolean fetchesCanonicalResource(IResourceValidator validator, String url) {
|
public boolean fetchesCanonicalResource(IResourceValidator validator, String url) {
|
||||||
return fetcher != null && fetcher.fetchesCanonicalResource(validator, url);
|
return fetcher != null && fetcher.fetchesCanonicalResource(validator, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -48,7 +48,7 @@ public class ValidatorUtils {
|
||||||
if (version.startsWith("3.0"))
|
if (version.startsWith("3.0"))
|
||||||
return new R3ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
return new R3ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
||||||
if (version.startsWith("4.0"))
|
if (version.startsWith("4.0"))
|
||||||
return new R4ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
return new R4ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5(), version);
|
||||||
if (version.startsWith("5.0"))
|
if (version.startsWith("5.0"))
|
||||||
return new R5ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
return new R5ToR5Loader(new String[]{"CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -7,10 +7,15 @@ import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r5.context.IWorkerContext.ICanonicalResourceLocator;
|
import org.hl7.fhir.r5.context.IWorkerContext.ICanonicalResourceLocator;
|
||||||
import org.hl7.fhir.r5.elementmodel.Element;
|
import org.hl7.fhir.r5.elementmodel.Element;
|
||||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.terminologies.TerminologyClient;
|
import org.hl7.fhir.r5.terminologies.TerminologyClient;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
@ -68,7 +73,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
||||||
Element.SpecialElement containingResourceType,
|
Element.SpecialElement containingResourceType,
|
||||||
String path,
|
String path,
|
||||||
String url) {
|
String url) {
|
||||||
return ContainedReferenceValidationPolicy.CHECK_TYPE;
|
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -276,4 +281,10 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodedContentValidationPolicy policyForCodedContent(IResourceValidator validator, Object appContext, String stackPath, ElementDefinition definition,
|
||||||
|
StructureDefinition structure, BindingKind kind, ValueSet valueSet, List<String> systems) {
|
||||||
|
return CodedContentValidationPolicy.VALUESET;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2042,7 +2042,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), fixedSource, "end", focus, pattern);
|
checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), fixedSource, "end", focus, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPrimitive(Object appContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node) throws FHIRException {
|
private void checkPrimitive(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node) throws FHIRException {
|
||||||
if (isBlank(e.primitiveValue())) {
|
if (isBlank(e.primitiveValue())) {
|
||||||
if (e.primitiveValue() == null)
|
if (e.primitiveValue() == null)
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, e.hasChildren(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_VALUEEXT);
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, e.hasChildren(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_VALUEEXT);
|
||||||
|
@ -2117,13 +2117,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
boolean found;
|
boolean found;
|
||||||
try {
|
try {
|
||||||
found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) ||
|
found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) ||
|
||||||
SpecialExtensions.isKnownExtension(url) || isXverUrl(url) || fetcher.resolveURL(this, appContext, path, url, type);
|
SpecialExtensions.isKnownExtension(url) || isXverUrl(url) || fetcher.resolveURL(this, hostContext, path, url, type);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
found = false;
|
found = false;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (type.equals("canonical")) {
|
if (type.equals("canonical")) {
|
||||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, appContext, path, url);
|
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url);
|
||||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2140,7 +2140,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (type.equals("canonical")) {
|
if (type.equals("canonical")) {
|
||||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, appContext, path, url);
|
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url);
|
||||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
|
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||||
try {
|
try {
|
||||||
Resource r = fetcher.fetchCanonicalResource(this, url);
|
Resource r = fetcher.fetchCanonicalResource(this, url);
|
||||||
|
@ -2276,7 +2276,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.hasBinding() && e.primitiveValue() != null) {
|
if (context.hasBinding() && e.primitiveValue() != null) {
|
||||||
checkPrimitiveBinding(errors, path, type, context, e, profile, node);
|
checkPrimitiveBinding(hostContext, errors, path, type, context, e, profile, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.equals("xhtml")) {
|
if (type.equals("xhtml")) {
|
||||||
|
@ -2540,7 +2540,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPrimitiveBinding(List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, Element element, StructureDefinition profile, NodeStack stack) {
|
private void checkPrimitiveBinding(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, Element element, StructureDefinition profile, NodeStack stack) {
|
||||||
// We ignore bindings that aren't on string, uri or code
|
// We ignore bindings that aren't on string, uri or code
|
||||||
if (!element.hasPrimitiveValue() || !("code".equals(type) || "string".equals(type) || "uri".equals(type) || "url".equals(type) || "canonical".equals(type))) {
|
if (!element.hasPrimitiveValue() || !("code".equals(type) || "string".equals(type) || "uri".equals(type) || "url".equals(type) || "canonical".equals(type))) {
|
||||||
return;
|
return;
|
||||||
|
@ -2561,29 +2561,37 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet()));
|
warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
long t = System.nanoTime();
|
CodedContentValidationPolicy validationPolicy = getPolicyAdvisor() == null ?
|
||||||
ValidationResult vr = null;
|
CodedContentValidationPolicy.VALUESET : getPolicyAdvisor().policyForCodedContent(this, hostContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, vs, new ArrayList<>());
|
||||||
if (binding.getStrength() != BindingStrength.EXAMPLE) {
|
|
||||||
ValidationOptions options = baseOptions.setLanguage(stack.getWorkingLang()).guessSystem();
|
if (validationPolicy != CodedContentValidationPolicy.IGNORE) {
|
||||||
vr = checkCodeOnServer(stack, vs, value, options);
|
long t = System.nanoTime();
|
||||||
}
|
ValidationResult vr = null;
|
||||||
timeTracker.tx(t, "vc "+value+"");
|
if (binding.getStrength() != BindingStrength.EXAMPLE) {
|
||||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
ValidationOptions options = baseOptions.setLanguage(stack.getWorkingLang()).guessSystem();
|
||||||
removeTrackedMessagesForLocation(errors, element, path);
|
if (validationPolicy == CodedContentValidationPolicy.CODE) {
|
||||||
}
|
options = options.noCheckValueSetMembership();
|
||||||
if (vr != null && !vr.isOk()) {
|
}
|
||||||
if (vr.IsNoService())
|
vr = checkCodeOnServer(stack, vs, value, options);
|
||||||
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_15, value);
|
}
|
||||||
else if (binding.getStrength() == BindingStrength.REQUIRED)
|
timeTracker.tx(t, "vc "+value+"");
|
||||||
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||||
else if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
|
removeTrackedMessagesForLocation(errors, element, path);
|
||||||
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);
|
if (vr != null && !vr.isOk()) {
|
||||||
else if (!noExtensibleWarnings && !isOkExtension(value, vs))
|
if (vr.IsNoService())
|
||||||
txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_15, value);
|
||||||
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
|
else if (binding.getStrength() == BindingStrength.REQUIRED)
|
||||||
if (baseOnly) {
|
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
||||||
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
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"), value, stack);
|
||||||
|
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, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
||||||
|
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
|
||||||
|
if (baseOnly) {
|
||||||
|
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -114,7 +114,8 @@ public class ComparisonTests {
|
||||||
BaseWorkerContext bc = (BaseWorkerContext) context;
|
BaseWorkerContext bc = (BaseWorkerContext) context;
|
||||||
boolean dupl = bc.isAllowLoadingDuplicates();
|
boolean dupl = bc.isAllowLoadingDuplicates();
|
||||||
bc.setAllowLoadingDuplicates(true);
|
bc.setAllowLoadingDuplicates(true);
|
||||||
context.loadFromPackage(npm, new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5()));
|
context.loadFromPackage(npm, new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"},
|
||||||
|
new NullLoaderKnowledgeProviderR5(), context.getVersion()));
|
||||||
bc.setAllowLoadingDuplicates(dupl);
|
bc.setAllowLoadingDuplicates(dupl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ public class UtilitiesXTests {
|
||||||
if (version.startsWith("3.0"))
|
if (version.startsWith("3.0"))
|
||||||
return new R3ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
return new R3ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
||||||
if (version.startsWith("4.0"))
|
if (version.startsWith("4.0"))
|
||||||
return new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5());
|
return new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProviderR5(), version);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.hl7.fhir.r5.formats.XmlParser;
|
||||||
import org.hl7.fhir.r5.model.Base;
|
import org.hl7.fhir.r5.model.Base;
|
||||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||||
import org.hl7.fhir.r5.model.Constants;
|
import org.hl7.fhir.r5.model.Constants;
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
import org.hl7.fhir.r5.model.FhirPublication;
|
import org.hl7.fhir.r5.model.FhirPublication;
|
||||||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||||
import org.hl7.fhir.r5.model.Patient;
|
import org.hl7.fhir.r5.model.Patient;
|
||||||
|
@ -46,6 +47,8 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||||
|
@ -527,6 +530,14 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||||
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodedContentValidationPolicy policyForCodedContent(IResourceValidator validator, Object appContext, String stackPath, ElementDefinition definition,
|
||||||
|
StructureDefinition structure, BindingKind kind, ValueSet valueSet, List<String> systems) {
|
||||||
|
if (content.has("validateCodedContent"))
|
||||||
|
return CodedContentValidationPolicy.valueOf(content.get("validateCodedContent").getAsString());
|
||||||
|
else
|
||||||
|
return CodedContentValidationPolicy.VALUESET;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException {
|
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type) throws IOException, FHIRException {
|
||||||
return !url.contains("example.org") && !url.startsWith("http://hl7.org/fhir/invalid");
|
return !url.contains("example.org") && !url.startsWith("http://hl7.org/fhir/invalid");
|
||||||
|
@ -581,4 +592,5 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||||
public boolean fetchesCanonicalResource(IResourceValidator validator, String url) {
|
public boolean fetchesCanonicalResource(IResourceValidator validator, String url) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue