Merge pull request #686 from hapifhir/gg-202112-validation-fixes-tx
Gg 202112 validation fixes tx
This commit is contained in:
commit
67d8d8c076
|
@ -111,6 +111,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
|
|||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.utilities.OIDUtils;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
|
@ -927,6 +928,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
@Override
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs) {
|
||||
ValidationContextCarrier ctxt = new ValidationContextCarrier();
|
||||
return validateCode(options, code, vs, ctxt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) {
|
||||
if (options == null) {
|
||||
options = ValidationOptions.defaults();
|
||||
}
|
||||
|
@ -946,7 +953,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (options.isUseClient()) {
|
||||
// ok, first we try to validate locally
|
||||
try {
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, this, ctxt);
|
||||
if (!vsc.isServerSide(code.getSystem())) {
|
||||
res = vsc.validateCode(code);
|
||||
if (txCache != null) {
|
||||
|
@ -1066,13 +1073,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
}
|
||||
if (vs != null) {
|
||||
if (isTxCaching && cacheId != null && cached.contains(vs.getUrl()+"|"+vs.getVersion())) {
|
||||
if (isTxCaching && cacheId != null && vs.getUrl() != null && cached.contains(vs.getUrl()+"|"+vs.getVersion())) {
|
||||
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()+(vs.hasVersion() ? "|"+vs.getVersion() : "")));
|
||||
} else if (options.getVsAsUrl()){
|
||||
pin.addParameter().setName("url").setValue(new StringType(vs.getUrl()));
|
||||
} else {
|
||||
pin.addParameter().setName("valueSet").setResource(vs);
|
||||
cached.add(vs.getUrl()+"|"+vs.getVersion());
|
||||
if (vs.getUrl() != null) {
|
||||
cached.add(vs.getUrl()+"|"+vs.getVersion());
|
||||
}
|
||||
}
|
||||
cache = true;
|
||||
addDependentResources(pin, vs);
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hl7.fhir.exceptions.DefinitionException;
|
|||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.ParserType;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
|
@ -64,11 +65,13 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
@ -193,13 +196,14 @@ public interface IWorkerContext {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public interface ICanonicalResourceLocator {
|
||||
void findResource(Object caller, String url); // if it can be found, put it in the context
|
||||
}
|
||||
|
||||
public interface IContextResourceLoader {
|
||||
/**
|
||||
* @return List of the resource types that shoud be loaded
|
||||
* @return List of the resource types that should be loaded
|
||||
*/
|
||||
String[] getTypes();
|
||||
|
||||
|
@ -244,7 +248,6 @@ public interface IWorkerContext {
|
|||
IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the versions of the definitions loaded in context
|
||||
* @return
|
||||
|
@ -745,6 +748,8 @@ public interface IWorkerContext {
|
|||
* @return
|
||||
*/
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs);
|
||||
|
||||
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt);
|
||||
|
||||
public void validateCodeBatch(ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs);
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
|
@ -69,12 +72,52 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
private IWorkerContext context;
|
||||
private Map<String, ValueSetCheckerSimple> inner = new HashMap<>();
|
||||
private ValidationOptions options;
|
||||
private ValidationContextCarrier localContext;
|
||||
private List<CodeSystem> localSystems = new ArrayList<>();
|
||||
|
||||
public ValueSetCheckerSimple(ValidationOptions options, ValueSet source, IWorkerContext context) {
|
||||
this.valueset = source;
|
||||
this.context = context;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public ValueSetCheckerSimple(ValidationOptions options, ValueSet source, IWorkerContext context, ValidationContextCarrier ctxt) {
|
||||
this.valueset = source;
|
||||
this.context = context;
|
||||
this.options = options;
|
||||
this.localContext = ctxt;
|
||||
analyseValueSet();
|
||||
}
|
||||
|
||||
private void analyseValueSet() {
|
||||
if (localContext != null) {
|
||||
if (valueset != null) {
|
||||
for (ConceptSetComponent i : valueset.getCompose().getInclude()) {
|
||||
analyseComponent(i);
|
||||
}
|
||||
for (ConceptSetComponent i : valueset.getCompose().getExclude()) {
|
||||
analyseComponent(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void analyseComponent(ConceptSetComponent i) {
|
||||
if (i.getSystemElement().hasExtension(ToolingExtensions.EXT_VALUESET_SYSTEM)) {
|
||||
String ref = i.getSystemElement().getExtensionString(ToolingExtensions.EXT_VALUESET_SYSTEM);
|
||||
if (ref.startsWith("#")) {
|
||||
String id = ref.substring(1);
|
||||
for (ValidationContextResourceProxy t : localContext.getResources()) {
|
||||
CodeSystem cs = (CodeSystem) t.loadContainedResource(id, CodeSystem.class);
|
||||
if (cs != null) {
|
||||
localSystems.add(cs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Not done yet #2: "+ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ValidationResult validateCode(CodeableConcept code) throws FHIRException {
|
||||
// first, we validate the codings themselves
|
||||
|
@ -85,7 +128,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (!c.hasSystem()) {
|
||||
warnings.add(context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE));
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(c.getSystem());
|
||||
CodeSystem cs = resolveCodeSystem(c.getSystem());
|
||||
ValidationResult res = null;
|
||||
if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) {
|
||||
res = context.validateCode(options.noClient(), c, null);
|
||||
|
@ -124,6 +167,19 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
}
|
||||
}
|
||||
|
||||
public CodeSystem resolveCodeSystem(String system) {
|
||||
for (CodeSystem t : localSystems) {
|
||||
if (t.getUrl().equals(system)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
if (cs == null) {
|
||||
cs = findSpecialCodeSystem(system);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
public ValidationResult validateCode(Coding code) throws FHIRException {
|
||||
String warningMessage = null;
|
||||
// first, we validate the concept itself
|
||||
|
@ -144,10 +200,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
}
|
||||
inExpansion = checkExpansion(code);
|
||||
inInclude = checkInclude(code);
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
if (cs == null) {
|
||||
cs = findSpecialCodeSystem(system);
|
||||
}
|
||||
CodeSystem cs = resolveCodeSystem(system);
|
||||
if (cs == null) {
|
||||
warningMessage = "Unable to resolve system "+system;
|
||||
if (!inExpansion) {
|
||||
|
@ -498,7 +551,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (vsi.hasFilter()) {
|
||||
return null;
|
||||
}
|
||||
CodeSystem cs = context.fetchCodeSystem(vsi.getSystem());
|
||||
CodeSystem cs = resolveCodeSystem(vsi.getSystem());
|
||||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -604,7 +657,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
if (!system.equals(vsi.getSystem()))
|
||||
return false;
|
||||
// ok, we need the code system
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
CodeSystem cs = resolveCodeSystem(system);
|
||||
if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
|
||||
// make up a transient value set with
|
||||
ValueSet vs = new ValueSet();
|
||||
|
@ -709,7 +762,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
return inner.get(url);
|
||||
}
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, url);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, context);
|
||||
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, context, localContext);
|
||||
inner.put(url, vsc);
|
||||
return vsc;
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ public class ToolingExtensions {
|
|||
public static final String EXT_BINARY_FORMAT = "http://hl7.org/fhir/StructureDefinition/implementationguide-resource-format";
|
||||
public static final String EXT_TARGET_ID = "http://hl7.org/fhir/StructureDefinition/targetElement";
|
||||
public static final String EXT_TARGET_PATH = "http://hl7.org/fhir/StructureDefinition/targetPath";
|
||||
public static final String EXT_VALUESET_SYSTEM = "http://hl7.org/fhir/StructureDefinition/valueset-system";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.model.Questionnaire;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
public class ValidationContextCarrier {
|
||||
/**
|
||||
*
|
||||
* When the validator is calling validateCode, it typically has a partially loaded resource that may provide
|
||||
* additional resources that are relevant to the validation. This is a handle back into the validator context
|
||||
* to ask for the resource to be fully loaded if it becomes relevant. Note that the resource may fail to load
|
||||
* (e.g. if it's part of what's being validated) and if it does, the validator will record the validation
|
||||
* issues before throwing an error
|
||||
*
|
||||
* This is a reference back int
|
||||
*
|
||||
*/
|
||||
public interface IValidationContextResourceLoader {
|
||||
public Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class<? extends Resource> class1) throws FHIRException;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of resources that provide context - typically, a container resource, and a bundle resource.
|
||||
* iterate these in order looking for contained resources
|
||||
*
|
||||
*/
|
||||
public static class ValidationContextResourceProxy {
|
||||
|
||||
// either a resource
|
||||
private Resource resource;
|
||||
|
||||
|
||||
// or an element and a loader
|
||||
private Element element;
|
||||
private IValidationContextResourceLoader loader;
|
||||
private List<ValidationMessage> errors;
|
||||
private String path;
|
||||
|
||||
public ValidationContextResourceProxy(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public ValidationContextResourceProxy(List<ValidationMessage> errors, String path, Element element, IValidationContextResourceLoader loader) {
|
||||
this.errors = errors;
|
||||
this.path = path;
|
||||
this.element = element;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public Resource loadContainedResource(String id, Class<? extends Resource> class1) throws FHIRException {
|
||||
if (resource == null) {
|
||||
Resource res = loader.loadContainedResource(errors, path, element, id, class1);
|
||||
return res;
|
||||
} else {
|
||||
if (resource instanceof DomainResource) {
|
||||
for (Resource r : ((DomainResource) resource).getContained()) {
|
||||
if (r.getId().equals(id)) {
|
||||
if (class1.isInstance(r))
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ValidationContextResourceProxy> resources = new ArrayList<>();
|
||||
|
||||
public List<ValidationContextResourceProxy> getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,11 +10,9 @@ public class SIDUtilities {
|
|||
public static List<String> codeSystemList() {
|
||||
List<String> codeSystems = new ArrayList<>();
|
||||
codeSystems.add("http://hl7.org/fhir/sid/ndc");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icd-10");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icpc2");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icd-9");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icd-10");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icpc2");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/cvx");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/srt");
|
||||
codeSystems.add("http://hl7.org/fhir/sid/icd-10-vn");
|
||||
|
@ -55,8 +53,38 @@ public class SIDUtilities {
|
|||
allSystems.addAll(idSystemList());
|
||||
return allSystems;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static boolean isInvalidVersion(String u, String v) {
|
||||
if (v == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (idSystemList().contains(u)) {
|
||||
return true;
|
||||
} else {
|
||||
switch (u) {
|
||||
case "http://hl7.org/fhir/sid/ndc":
|
||||
return v.matches("[\\d]{8}");
|
||||
case "http://hl7.org/fhir/sid/icpc2":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/icd-10":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/icd-9":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/cvx":
|
||||
return v.matches("[\\d]{8}");
|
||||
case "http://hl7.org/fhir/sid/srt":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/icd-10-vn":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/icd-10-cm":
|
||||
return false;
|
||||
case "http://hl7.org/fhir/sid/icd-9-cm":
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -397,7 +397,6 @@ public class VersionUtilities {
|
|||
|
||||
}
|
||||
if (isR4Ver(version)) {
|
||||
|
||||
res.add("CodeSystem");
|
||||
res.add("ActivityDefinition");
|
||||
res.add("CapabilityStatement");
|
||||
|
@ -429,6 +428,38 @@ public class VersionUtilities {
|
|||
res.add("TestScript");
|
||||
res.add("ValueSet");
|
||||
}
|
||||
if (isR4BVer(version)) {
|
||||
res.add("ActivityDefinition");
|
||||
res.add("CapabilityStatement");
|
||||
res.add("ChargeItemDefinition");
|
||||
res.add("Citation");
|
||||
res.add("CodeSystem");
|
||||
res.add("CompartmentDefinition");
|
||||
res.add("ConceptMap");
|
||||
res.add("EventDefinition");
|
||||
res.add("Evidence");
|
||||
res.add("EvidenceReport");
|
||||
res.add("EvidenceVariable");
|
||||
res.add("ExampleScenario");
|
||||
res.add("GraphDefinition");
|
||||
res.add("ImplementationGuide");
|
||||
res.add("Library");
|
||||
res.add("Measure");
|
||||
res.add("MessageDefinition");
|
||||
res.add("NamingSystem");
|
||||
res.add("OperationDefinition");
|
||||
res.add("PlanDefinition");
|
||||
res.add("Questionnaire");
|
||||
res.add("ResearchDefinition");
|
||||
res.add("ResearchElementDefinition");
|
||||
res.add("SearchParameter");
|
||||
res.add("StructureDefinition");
|
||||
res.add("StructureMap");
|
||||
res.add("SubscriptionTopic");
|
||||
res.add("TerminologyCapabilities");
|
||||
res.add("TestScript");
|
||||
res.add("ValueSet");
|
||||
}
|
||||
|
||||
if (isR5Ver(version) || "current".equals(version)) {
|
||||
|
||||
|
|
|
@ -514,6 +514,7 @@ public class I18nConstants {
|
|||
public static final String TYPE_SPECIFIC_CHECKS_DT_URL_EXAMPLE = "TYPE_SPECIFIC_CHECKS_DT_URL_EXAMPLE";
|
||||
public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE";
|
||||
public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE";
|
||||
public static final String TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE_NC = "TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE_NC";
|
||||
public static final String TYPE_SPECIFIC_CHECKS_DT_UUID_STRAT = "Type_Specific_Checks_DT_UUID_Strat";
|
||||
public static final String TYPE_SPECIFIC_CHECKS_DT_UUID_VALID = "Type_Specific_Checks_DT_UUID_Valid";
|
||||
public static final String UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER = "Unable_to_connect_to_terminology_server";
|
||||
|
|
|
@ -645,6 +645,7 @@ SD_ED_BIND_NO_BINDABLE = The element {0} has a binding, but no bindable types ar
|
|||
DISCRIMINATOR_BAD_PATH = Error processing path expression for discriminator: {0} (src = ''{1}'')
|
||||
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_NC = Canonical URL ''{0}'' exists, but can't be loaded, so it can't be checked for validity
|
||||
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
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.hl7.fhir.r5.model.*;
|
|||
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
@ -61,7 +62,8 @@ import java.util.Map;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class BaseValidator {
|
||||
public class BaseValidator implements IValidationContextResourceLoader {
|
||||
|
||||
public class TrackedLocationRelatedMessage {
|
||||
private Object location;
|
||||
private ValidationMessage vmsg;
|
||||
|
@ -996,7 +998,8 @@ public class BaseValidator {
|
|||
}
|
||||
}
|
||||
|
||||
protected Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class class1) throws FHIRException {
|
||||
@Override
|
||||
public Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class<? extends Resource> class1) throws FHIRException {
|
||||
for (Element contained : resource.getChildren("contained")) {
|
||||
if (contained.getIdBase().equals(id)) {
|
||||
return loadFoundResource(errors, path, contained, class1);
|
||||
|
@ -1005,7 +1008,7 @@ public class BaseValidator {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected Resource loadFoundResource(List<ValidationMessage> errors, String path, Element resource, Class class1) throws FHIRException {
|
||||
protected Resource loadFoundResource(List<ValidationMessage> errors, String path, Element resource, Class<? extends Resource> class1) throws FHIRException {
|
||||
try {
|
||||
FhirPublication v = FhirPublication.fromCode(context.getVersion());
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
|
|
|
@ -2114,52 +2114,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, Utilities.isAbsoluteUrl(url),
|
||||
node.isContained() ? I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_CONTAINED : I18nConstants.TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE, url);
|
||||
} else {
|
||||
// now, do we check the URI target?
|
||||
if (fetcher != null && !type.equals("uuid")) {
|
||||
boolean found;
|
||||
try {
|
||||
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, hostContext, path, url, type);
|
||||
} catch (IOException e1) {
|
||||
found = false;
|
||||
}
|
||||
if (!found) {
|
||||
if (type.equals("canonical")) {
|
||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url);
|
||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||
} else {
|
||||
hint(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||
}
|
||||
} else {
|
||||
if (url.contains("hl7.org") || url.contains("fhir.org")) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url);
|
||||
} else if (url.contains("example.org") || url.contains("acme.com")) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_EXAMPLE, url);
|
||||
} else {
|
||||
warning(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (type.equals("canonical")) {
|
||||
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) {
|
||||
try {
|
||||
Resource r = fetcher.fetchCanonicalResource(this, url);
|
||||
if (r == null) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||
} else if (rule(errors, IssueType.INVALID, e.line(), e.col(), path, isCorrectCanonicalType(r, context), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE, url, r.fhirType(), listExpectedCanonicalTypes(context))) {
|
||||
if (rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||
// todo....
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// won't happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validateReference(hostContext, errors, path, type, context, e, url);
|
||||
}
|
||||
}
|
||||
if (type.equals(ID) && !"Resource.id".equals(context.getBase().getPath())) {
|
||||
|
@ -2323,6 +2278,67 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// for nothing to check
|
||||
}
|
||||
|
||||
public void validateReference(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, String url) {
|
||||
// now, do we check the URI target?
|
||||
if (fetcher != null && !type.equals("uuid")) {
|
||||
boolean found;
|
||||
try {
|
||||
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);
|
||||
if (!found) {
|
||||
found = fetcher.resolveURL(this, hostContext, path, url, type);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
found = false;
|
||||
}
|
||||
if (!found) {
|
||||
if (type.equals("canonical")) {
|
||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, hostContext, path, url);
|
||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||
} else {
|
||||
hint(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url);
|
||||
}
|
||||
} else {
|
||||
if (url.contains("hl7.org") || url.contains("fhir.org")) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url);
|
||||
} else if (url.contains("example.org") || url.contains("acme.com")) {
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_EXAMPLE, url);
|
||||
} else {
|
||||
warning(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (type.equals("canonical")) {
|
||||
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) {
|
||||
try {
|
||||
Resource r = null;
|
||||
if (url.startsWith("#")) {
|
||||
r = loadContainedResource(errors, path, hostContext.getRootResource(), url.substring(1), Resource.class);
|
||||
}
|
||||
if (r == null) {
|
||||
fetcher.fetchCanonicalResource(this, url);
|
||||
}
|
||||
if (r == null) {
|
||||
r = this.context.fetchResource(Resource.class, url);
|
||||
}
|
||||
if (r == null) {
|
||||
warning(errors, IssueType.INVALID, e.line(), e.col(), path, rp != ReferenceValidationPolicy.CHECK_VALID, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE_NC, url);
|
||||
} else if (rule(errors, IssueType.INVALID, e.line(), e.col(), path, isCorrectCanonicalType(r, context), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_TYPE, url, r.fhirType(), listExpectedCanonicalTypes(context))) {
|
||||
if (rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||
// todo....
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// won't happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> listExpectedCanonicalTypes(ElementDefinition context) {
|
||||
List<String> res = new ArrayList<>();
|
||||
TypeRefComponent tr = context.getType("canonical");
|
||||
|
@ -2354,11 +2370,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
private boolean isCorrectCanonicalType(Resource r, CanonicalType p) {
|
||||
String url = p.getValue();
|
||||
if (url != null && url.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
url = url.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
return Utilities.existsInList(url, "Resource", "CanonicalResource") || url.equals(r.fhirType());
|
||||
String t = null;
|
||||
if (url.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
t = url.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
} else {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||
if (sd != null) {
|
||||
t = sd.getType();
|
||||
}
|
||||
}
|
||||
if (t == null ) {
|
||||
return false;
|
||||
} else {
|
||||
return Utilities.existsInList(t, "Resource", "CanonicalResource") || t.equals(r.fhirType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCanonicalURLElement(Element e) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.attoparser.config.ParseConfiguration.ElementBalancing;
|
||||
import org.hl7.fhir.convertors.conv10_50.VersionConvertor_10_50;
|
||||
import org.hl7.fhir.convertors.conv14_50.VersionConvertor_14_50;
|
||||
import org.hl7.fhir.convertors.conv30_50.VersionConvertor_30_50;
|
||||
|
@ -40,6 +41,8 @@ import org.hl7.fhir.r5.model.TimeType;
|
|||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
|
@ -52,6 +55,7 @@ import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
|
|||
import org.hl7.fhir.validation.TimeTracker;
|
||||
import org.hl7.fhir.validation.instance.EnableWhenEvaluator;
|
||||
import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack;
|
||||
import org.hl7.fhir.validation.instance.type.QuestionnaireValidator.ElementWithIndex;
|
||||
import org.hl7.fhir.validation.instance.type.QuestionnaireValidator.QuestionnaireWithContext;
|
||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
|
||||
|
@ -60,6 +64,26 @@ import ca.uhn.fhir.util.ObjectUtil;
|
|||
|
||||
public class QuestionnaireValidator extends BaseValidator {
|
||||
|
||||
public class ElementWithIndex {
|
||||
|
||||
private Element element;
|
||||
private int index;
|
||||
|
||||
public ElementWithIndex(Element element, int index) {
|
||||
this.element = element;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class QuestionnaireWithContext {
|
||||
private Questionnaire q;
|
||||
private Element container;
|
||||
|
@ -88,7 +112,7 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
public Questionnaire q() {
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private EnableWhenEvaluator myEnableWhenEvaluator;
|
||||
|
@ -263,8 +287,9 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
if (answers.size() > 1)
|
||||
rule(errors, IssueType.INVALID, answers.get(1).line(), answers.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), I18nConstants.QUESTIONNAIRE_QR_ITEM_ONLYONEA);
|
||||
|
||||
int i = 0;
|
||||
for (Element answer : answers) {
|
||||
NodeStack ns = stack.push(answer, -1, null, null);
|
||||
NodeStack ns = stack.push(answer, i, null, null);
|
||||
if (qItem.getType() != null) {
|
||||
switch (qItem.getType()) {
|
||||
case GROUP:
|
||||
|
@ -337,12 +362,15 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
case NULL:
|
||||
// no validation
|
||||
break;
|
||||
case QUESTION:
|
||||
throw new Error("Shouldn't get here?");
|
||||
}
|
||||
}
|
||||
if (qItem.getType() != QuestionnaireItemType.GROUP) {
|
||||
// if it's a group, we already have an error before getting here, so no need to hammer away on that
|
||||
validateQuestionannaireResponseItems(hostContext, qsrc, qItem.getItem(), errors, answer, stack, inProgress, questionnaireResponseRoot, qstack);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (qItem.getType() == null) {
|
||||
fail(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTYPE, qItem.getLinkId());
|
||||
|
@ -363,14 +391,13 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
return !answers.isEmpty() || !qItem.getRequired() || qItem.getType() == QuestionnaireItemType.GROUP;
|
||||
}
|
||||
|
||||
private void validateQuestionnaireResponseItem(ValidatorHostContext hostcontext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<Element> elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
|
||||
if (elements.size() > 1)
|
||||
rule(errors, IssueType.INVALID, elements.get(1).line(), elements.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), I18nConstants.QUESTIONNAIRE_QR_ITEM_ONLYONEI, qItem.getLinkId());
|
||||
int i = 0;
|
||||
for (Element element : elements) {
|
||||
NodeStack ns = stack.push(element, i, null, null);
|
||||
validateQuestionnaireResponseItem(hostcontext, qsrc, qItem, errors, element, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, element));
|
||||
i++;
|
||||
private void validateQuestionnaireResponseItem(ValidatorHostContext hostcontext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<ElementWithIndex> elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
|
||||
if (elements.size() > 1) {
|
||||
rule(errors, IssueType.INVALID, elements.get(1).getElement().line(), elements.get(1).getElement().col(), stack.getLiteralPath(), qItem.getRepeats(), I18nConstants.QUESTIONNAIRE_QR_ITEM_ONLYONEI, qItem.getLinkId());
|
||||
}
|
||||
for (ElementWithIndex element : elements) {
|
||||
NodeStack ns = stack.push(element.getElement(), element.getIndex(), null, null);
|
||||
validateQuestionnaireResponseItem(hostcontext, qsrc, qItem, errors, element.getElement(), ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, element.getElement()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,8 +413,9 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
List<Element> items = new ArrayList<Element>();
|
||||
element.getNamedChildren("item", items);
|
||||
// now, sort into stacks
|
||||
Map<String, List<Element>> map = new HashMap<String, List<Element>>();
|
||||
Map<String, List<ElementWithIndex>> map = new HashMap<String, List<ElementWithIndex>>();
|
||||
int lastIndex = -1;
|
||||
int counter = 0;
|
||||
for (Element item : items) {
|
||||
String linkId = item.getNamedChildValue("linkId");
|
||||
if (rule(errors, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), I18nConstants.QUESTIONNAIRE_QR_ITEM_NOLINKID)) {
|
||||
|
@ -396,7 +424,7 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
QuestionnaireItemComponent qItem = findQuestionnaireItem(qsrc, linkId);
|
||||
if (qItem != null) {
|
||||
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index > -1, misplacedItemError(qItem));
|
||||
NodeStack ns = stack.push(item, -1, null, null);
|
||||
NodeStack ns = stack.push(item, counter, null, null);
|
||||
validateQuestionnaireResponseItem(hostContext, qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, item));
|
||||
} else
|
||||
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTFOUND, linkId);
|
||||
|
@ -407,29 +435,28 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
// If an item has a child called "linkId" but no child called "answer",
|
||||
// we'll treat it as not existing for the purposes of enableWhen validation
|
||||
if (item.hasChildren("answer") || item.hasChildren("item")) {
|
||||
List<Element> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
|
||||
mapItem.add(item);
|
||||
List<ElementWithIndex> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
|
||||
mapItem.add(new ElementWithIndex(item, counter));
|
||||
}
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
// ok, now we have a list of known items, grouped by linkId. We've made an error for anything out of order
|
||||
for (QuestionnaireItemComponent qItem : qItems) {
|
||||
List<Element> mapItem = map.get(qItem.getLinkId());
|
||||
List<ElementWithIndex> mapItem = map.get(qItem.getLinkId());
|
||||
validateQuestionnaireResponseItem(hostContext, qsrc, errors, element, stack, inProgress, questionnaireResponseRoot, qItem, mapItem, qstack);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateQuestionnaireResponseItem(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List<Element> mapItem, QStack qstack) {
|
||||
public void validateQuestionnaireResponseItem(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List<ElementWithIndex> mapItem, QStack qstack) {
|
||||
boolean enabled = myEnableWhenEvaluator.isQuestionEnabled(hostContext, qItem, qstack, fpe);
|
||||
if (mapItem != null) {
|
||||
if (!enabled) {
|
||||
int i = 0;
|
||||
for (Element e : mapItem) {
|
||||
NodeStack ns = stack.push(e, i, e.getProperty().getDefinition(), e.getProperty().getDefinition());
|
||||
rule(errors, IssueType.INVALID, e.line(), e.col(), ns.getLiteralPath(), enabled, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTENABLED2, qItem.getLinkId());
|
||||
i++;
|
||||
for (ElementWithIndex e : mapItem) {
|
||||
NodeStack ns = stack.push(e.getElement(), e.getElement().getIndex(), e.getElement().getProperty().getDefinition(), e.getElement().getProperty().getDefinition());
|
||||
rule(errors, IssueType.INVALID, e.getElement().line(), e.getElement().col(), ns.getLiteralPath(), enabled, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTENABLED2, qItem.getLinkId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,7 +543,8 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
}
|
||||
|
||||
long t = System.nanoTime();
|
||||
ValidationResult res = context.validateCode(new ValidationOptions(stack.getWorkingLang()), c, vs);
|
||||
ValidationContextCarrier vc = makeValidationContext(errors, qSrc);
|
||||
ValidationResult res = context.validateCode(new ValidationOptions(stack.getWorkingLang()), c, vs, vc);
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (!res.isOk()) {
|
||||
txRule(errors, res.getTxLink(), IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, I18nConstants.QUESTIONNAIRE_QR_ITEM_BADOPTION, c.getSystem(), c.getCode());
|
||||
|
@ -529,6 +557,16 @@ public class QuestionnaireValidator extends BaseValidator {
|
|||
}
|
||||
}
|
||||
|
||||
private ValidationContextCarrier makeValidationContext(List<ValidationMessage> errors, QuestionnaireWithContext qSrc) {
|
||||
ValidationContextCarrier vc = new ValidationContextCarrier();
|
||||
if (qSrc.container == null) {
|
||||
vc.getResources().add(new ValidationContextResourceProxy(qSrc.q));
|
||||
} else {
|
||||
vc.getResources().add(new ValidationContextResourceProxy(errors, qSrc.containerPath, qSrc.container, this));
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
private void validateAnswerCode(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean theOpenChoice) {
|
||||
Element v = answer.getNamedChild("valueCoding");
|
||||
NodeStack ns = stack.push(v, -1, null, null);
|
||||
|
|
Loading…
Reference in New Issue