add check for multiple version matches for a versionless canonical reference
This commit is contained in:
parent
209d38413e
commit
13dcebb3e4
|
@ -3299,4 +3299,95 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String uri) {
|
||||
List<T> res = new ArrayList<>();
|
||||
if (uri != null && !uri.startsWith("#")) {
|
||||
if (class_ == StructureDefinition.class) {
|
||||
uri = ProfileUtilities.sdNs(uri, null);
|
||||
}
|
||||
assert !uri.contains("|");
|
||||
if (uri.contains("#")) {
|
||||
uri = uri.substring(0, uri.indexOf("#"));
|
||||
}
|
||||
synchronized (lock) {
|
||||
if (class_ == Resource.class || class_ == null) {
|
||||
for (Map<String, ResourceProxy> rt : allResourcesById.values()) {
|
||||
for (ResourceProxy r : rt.values()) {
|
||||
if (uri.equals(r.getUrl())) {
|
||||
res.add((T) r.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (class_ == ImplementationGuide.class || class_ == Resource.class || class_ == null) {
|
||||
for (ImplementationGuide cr : guides.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == CapabilityStatement.class || class_ == Resource.class || class_ == null) {
|
||||
for (CapabilityStatement cr : capstmts.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == Measure.class || class_ == Resource.class || class_ == null) {
|
||||
for (Measure cr : measures.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == Library.class || class_ == Resource.class || class_ == null) {
|
||||
for (Library cr : libraries.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == StructureDefinition.class || class_ == Resource.class || class_ == null) {
|
||||
for (StructureDefinition cr : structures.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == StructureMap.class || class_ == Resource.class || class_ == null) {
|
||||
for (StructureMap cr : transforms.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == NamingSystem.class || class_ == Resource.class || class_ == null) {
|
||||
for (NamingSystem cr : systems.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == ValueSet.class || class_ == Resource.class || class_ == null) {
|
||||
for (ValueSet cr : valueSets.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == CodeSystem.class || class_ == Resource.class || class_ == null) {
|
||||
for (CodeSystem cr : codeSystems.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == ConceptMap.class || class_ == Resource.class || class_ == null) {
|
||||
for (ConceptMap cr : maps.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == ActorDefinition.class || class_ == Resource.class || class_ == null) {
|
||||
for (ActorDefinition cr : actors.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == Requirements.class || class_ == Resource.class || class_ == null) {
|
||||
for (Requirements cr : requirements.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == PlanDefinition.class || class_ == Resource.class || class_ == null) {
|
||||
for (PlanDefinition cr : plans.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == OperationDefinition.class || class_ == Resource.class || class_ == null) {
|
||||
for (OperationDefinition cr : operations.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == Questionnaire.class || class_ == Resource.class || class_ == null) {
|
||||
for (Questionnaire cr : questionnaires.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
} else if (class_ == SearchParameter.class || class_ == Resource.class || class_ == null) {
|
||||
for (SearchParameter cr : searchParameters.getForUrl(uri)) {
|
||||
res.add((T) cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -537,6 +537,16 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
|
|||
}
|
||||
}
|
||||
|
||||
public List<T> getForUrl(String url) {
|
||||
List<T> res = new ArrayList<>();
|
||||
List<CanonicalResourceManager<T>.CachedCanonicalResource<T>> list = listForUrl.get(url);
|
||||
if (list != null) {
|
||||
for (CanonicalResourceManager<T>.CachedCanonicalResource<T> t : list) {
|
||||
res.add(t.getResource());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is asking for a packaged version aware resolution
|
||||
|
|
|
@ -191,6 +191,15 @@ public interface IWorkerContext {
|
|||
public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_, FhirPublication fhirVersion);
|
||||
public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch all the resources for the given URL - all matching versions
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String url);
|
||||
|
||||
/**
|
||||
* Variation of fetchResource when you have a string type, and don't need the right class
|
||||
*
|
||||
|
|
|
@ -6,7 +6,9 @@ import org.hl7.fhir.r5.model.CanonicalResource;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public interface IValidatorResourceFetcher {
|
||||
|
||||
|
@ -27,7 +29,7 @@ public interface IValidatorResourceFetcher {
|
|||
* @return an R5 version of the resource
|
||||
* @throws URISyntaxException
|
||||
*/
|
||||
CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException;
|
||||
CanonicalResource fetchCanonicalResource(IResourceValidator validator, Object appContext, String url) throws URISyntaxException;
|
||||
|
||||
/**
|
||||
* Whether to try calling fetchCanonicalResource for this reference (not whether it will succeed - just throw an exception from fetchCanonicalResource if it doesn't resolve. This is a policy thing.
|
||||
|
@ -38,4 +40,6 @@ public interface IValidatorResourceFetcher {
|
|||
* @return
|
||||
*/
|
||||
boolean fetchesCanonicalResource(IResourceValidator validator, String url);
|
||||
|
||||
Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.hl7.fhir.r5.context;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.PackageInformation;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
@ -16,6 +17,8 @@ import net.sourceforge.plantuml.tim.stdlib.GetVariableValue;
|
|||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -85,6 +88,11 @@ public class BaseWorkerContextTests {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String url) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
};
|
||||
baseWorkerContext.expParameters = new Parameters();
|
||||
return baseWorkerContext;
|
||||
|
|
|
@ -67,6 +67,8 @@ import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
|||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
|
@ -177,7 +179,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
protected String sessionId = Utilities.makeUuidLC();
|
||||
protected List<UsageContext> usageContexts = new ArrayList<UsageContext>();
|
||||
protected ValidationOptions baseOptions = new ValidationOptions(FhirPublication.R5);
|
||||
|
||||
protected IValidatorResourceFetcher fetcher;
|
||||
|
||||
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) {
|
||||
super();
|
||||
|
@ -210,6 +212,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
this.urlRegex = parent.urlRegex;
|
||||
this.usageContexts.addAll(parent.usageContexts);
|
||||
this.baseOptions = parent.baseOptions;
|
||||
this.fetcher = parent.fetcher;
|
||||
}
|
||||
|
||||
private boolean doingLevel(IssueSeverity error) {
|
||||
|
@ -1262,13 +1265,15 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
String[] refBaseParts = ref.substring(0, ref.indexOf("/_history/")).split("/");
|
||||
resourceType = refBaseParts[0];
|
||||
id = refBaseParts[1];
|
||||
targetUrl = base + resourceType+"/"+ id;
|
||||
} else if (base.startsWith("urn")) {
|
||||
resourceType = ref.split("/")[0];
|
||||
id = ref.split("/")[1];
|
||||
} else
|
||||
id = ref;
|
||||
|
||||
targetUrl = base + id;
|
||||
} else {
|
||||
id = ref;
|
||||
targetUrl = base + id;
|
||||
}
|
||||
}
|
||||
|
||||
List<Element> entries = new ArrayList<Element>();
|
||||
|
@ -1621,4 +1626,6 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
private boolean isContext(Coding use, Coding value, UsageContext usage) {
|
||||
return usage.getValue() instanceof Coding && context.subsumes(baseOptions, usage.getCode(), use) && context.subsumes(baseOptions, (Coding) usage.getValue(), value);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,9 +14,11 @@ import java.util.Arrays;
|
|||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.fhir.ucum.UcumEssenceService;
|
||||
|
@ -1194,7 +1196,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException {
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, Object appContext, String url) throws URISyntaxException {
|
||||
Resource res = context.fetchResource(Resource.class, url);
|
||||
if (res != null) {
|
||||
if (res instanceof CanonicalResource) {
|
||||
|
@ -1203,7 +1205,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
return null;
|
||||
}
|
||||
}
|
||||
return fetcher != null ? fetcher.fetchCanonicalResource(validator, url) : null;
|
||||
return fetcher != null ? fetcher.fetchCanonicalResource(validator, appContext, url) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1234,4 +1236,18 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
return EnumSet.allOf(ElementValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
Set<String> res = new HashSet<>();
|
||||
for (Resource r : context.fetchResourcesByUrl(Resource.class, url)) {
|
||||
if (r instanceof CanonicalResource) {
|
||||
res.add(((CanonicalResource) r).getVersion());
|
||||
}
|
||||
}
|
||||
if (fetcher != null) {
|
||||
res.addAll(fetcher.fetchCanonicalResourceVersions(validator, appContext, url));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ import java.net.URISyntaxException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -272,7 +274,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
}
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException {
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, Object appContext, String url) throws URISyntaxException {
|
||||
if (url.contains("|")) {
|
||||
url = url.substring(0, url.indexOf("|"));
|
||||
}
|
||||
|
@ -327,4 +329,9 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
return EnumSet.allOf(CodedContentValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -584,7 +584,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean noBindingMsgSuppressed;
|
||||
private Map<String, Element> fetchCache = new HashMap<>();
|
||||
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
|
||||
private IValidatorResourceFetcher fetcher;
|
||||
private IValidationPolicyAdvisor policyAdvisor;
|
||||
long time = 0;
|
||||
long start = 0;
|
||||
|
@ -673,14 +672,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return this;
|
||||
}
|
||||
|
||||
public IValidatorResourceFetcher getFetcher() {
|
||||
return this.fetcher;
|
||||
}
|
||||
|
||||
public IResourceValidator setFetcher(IValidatorResourceFetcher value) {
|
||||
this.fetcher = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValidationPolicyAdvisor getPolicyAdvisor() {
|
||||
|
@ -3118,7 +3109,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
r = loadContainedResource(errors, path, valContext.getRootResource(), url.substring(1), Resource.class);
|
||||
}
|
||||
if (r == null) {
|
||||
r = fetcher.fetchCanonicalResource(this, url);
|
||||
r = fetcher.fetchCanonicalResource(this, valContext.getAppContext(), url);
|
||||
}
|
||||
if (r == null) {
|
||||
r = this.context.fetchResource(Resource.class, url);
|
||||
|
@ -3129,6 +3120,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||
// todo....
|
||||
}
|
||||
// we resolved one, but if there's no version, check if the reference is potentially ambiguous
|
||||
if (!url.contains("|") && r instanceof CanonicalResource) {
|
||||
if (!Utilities.existsInList(context.getBase().getPath(), "ImplementationGuide.dependsOn.uri", "ConceptMap.group.source", "ConceptMap.group.target")) {
|
||||
// ImplementationGuide.dependsOn.version is mandatory, and ConceptMap is checked in the ConceptMap validator
|
||||
Set<String> possibleVersions = fetcher.fetchCanonicalResourceVersions(this, valContext.getAppContext(), url);
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, possibleVersions.size() <= 1, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS,
|
||||
url, ((CanonicalResource) r).getVersion(), CommaSeparatedStringBuilder.join(", ", Utilities.sorted(possibleVersions)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
|
@ -3341,11 +3341,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (!Utilities.noString(href) && href.startsWith("#") && !href.equals("#")) {
|
||||
String ref = href.substring(1);
|
||||
valContext.getInternalRefs().add(ref);
|
||||
int count = countTargetMatches(resource, ref, true);
|
||||
Set<String> refs = new HashSet<>();
|
||||
int count = countTargetMatches(resource, ref, true, "$", refs);
|
||||
if (count == 0) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_XHTML_RESOLVE, href, xpath, node.allText());
|
||||
} else if (count > 1) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES, href, xpath, node.allText());
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES, href, xpath, node.allText(), CommaSeparatedStringBuilder.join(", ", refs));
|
||||
}
|
||||
} else {
|
||||
// we can't validate at this point. Come back and revisit this some time in the future
|
||||
|
@ -3360,24 +3361,25 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
|
||||
protected int countTargetMatches(Element element, String fragment, boolean checkBundle) {
|
||||
protected int countTargetMatches(Element element, String fragment, boolean checkBundle, String path,Set<String> refs) {
|
||||
int count = 0;
|
||||
if (fragment.equals(element.getIdBase())) {
|
||||
count++;
|
||||
refs.add(path+"/id");
|
||||
}
|
||||
if (element.getXhtml() != null) {
|
||||
count = count + countTargetMatches(element.getXhtml(), fragment);
|
||||
count = count + countTargetMatches(element.getXhtml(), fragment, path, refs);
|
||||
}
|
||||
if (element.hasChildren()) {
|
||||
for (Element child : element.getChildren()) {
|
||||
count = count + countTargetMatches(child, fragment, false);
|
||||
count = count + countTargetMatches(child, fragment, false, path+"/"+child.getName(), refs);
|
||||
}
|
||||
}
|
||||
if (count == 0 && checkBundle) {
|
||||
Element e = element.getParentForValidator();
|
||||
while (e != null) {
|
||||
if (e.fhirType().equals("Bundle")) {
|
||||
return countTargetMatches(e, fragment, false);
|
||||
return countTargetMatches(e, fragment, false, path+"/..", refs);
|
||||
}
|
||||
e = e.getParentForValidator();
|
||||
}
|
||||
|
@ -3385,17 +3387,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return count;
|
||||
}
|
||||
|
||||
private int countTargetMatches(XhtmlNode node, String fragment) {
|
||||
private int countTargetMatches(XhtmlNode node, String fragment, String path,Set<String> refs) {
|
||||
int count = 0;
|
||||
if (fragment.equals(node.getAttribute("id"))) {
|
||||
count++;
|
||||
refs.add(path+"/@id");
|
||||
}
|
||||
if ("a".equals(node.getName()) && fragment.equals(node.getAttribute("name"))) {
|
||||
count++;
|
||||
refs.add(path+"/@name");
|
||||
}
|
||||
if (node.hasChildren()) {
|
||||
for (XhtmlNode child : node.getChildNodes()) {
|
||||
count = count + countTargetMatches(child, fragment);
|
||||
count = count + countTargetMatches(child, fragment, path+"/"+child.getName(), refs);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@ -5461,7 +5465,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else if (!fetcher.fetchesCanonicalResource(this, profile.primitiveValue())) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath() + ".meta.profile[" + i + "]", false, I18nConstants.VALIDATION_VAL_PROFILE_UNKNOWN_NOT_POLICY, profile.primitiveValue());
|
||||
} else {
|
||||
sd = lookupProfileReference(errors, element, stack, i, profile, sd);
|
||||
sd = lookupProfileReference(valContext, errors, element, stack, i, profile, sd);
|
||||
}
|
||||
}
|
||||
if (sd != null) {
|
||||
|
@ -5528,7 +5532,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ok;
|
||||
}
|
||||
|
||||
private StructureDefinition lookupProfileReference(List<ValidationMessage> errors, Element element, NodeStack stack,
|
||||
private StructureDefinition lookupProfileReference(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack,
|
||||
int i, Element profile, StructureDefinition sd) {
|
||||
String url = profile.primitiveValue();
|
||||
CanonicalResourceLookupResult cr = crLookups.get(url);
|
||||
|
@ -5540,7 +5544,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
sd = (StructureDefinition) fetcher.fetchCanonicalResource(this, url);
|
||||
sd = (StructureDefinition) fetcher.fetchCanonicalResource(this, valContext.getAppContext(), url);
|
||||
crLookups.put(url, new CanonicalResourceLookupResult(sd));
|
||||
} catch (Exception e) {
|
||||
if (STACK_TRACE) { e.printStackTrace(); }
|
||||
|
@ -5689,7 +5693,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else if (element.getType().equals("CodeSystem")) {
|
||||
return new CodeSystemValidator(this).validateCodeSystem(valContext, errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok;
|
||||
} else if (element.getType().equals("ConceptMap")) {
|
||||
return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok;
|
||||
return new ConceptMapValidator(this).validateConceptMap(valContext, errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok;
|
||||
} else if (element.getType().equals("SearchParameter")) {
|
||||
return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("StructureDefinition")) {
|
||||
|
@ -5697,7 +5701,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else if (element.getType().equals("StructureMap")) {
|
||||
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("ValueSet")) {
|
||||
return new ValueSetValidator(this).validateValueSet(errors, element, stack) && ok;
|
||||
return new ValueSetValidator(this).validateValueSet(valContext, errors, element, stack) && ok;
|
||||
} else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) {
|
||||
if (element.getNativeObject() != null && element.getNativeObject() instanceof JsonObject) {
|
||||
JsonObject json = (JsonObject) element.getNativeObject();
|
||||
|
@ -7726,4 +7730,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return this;
|
||||
}
|
||||
|
||||
public IValidatorResourceFetcher getFetcher() {
|
||||
return this.fetcher;
|
||||
}
|
||||
|
||||
public IResourceValidator setFetcher(IValidatorResourceFetcher value) {
|
||||
this.fetcher = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
|
@ -17,6 +18,7 @@ import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest;
|
|||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
@ -24,6 +26,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
|||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.hl7.fhir.validation.BaseValidator;
|
||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||
|
||||
|
||||
public class ConceptMapValidator extends BaseValidator {
|
||||
|
@ -109,7 +112,7 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
super(parent);
|
||||
}
|
||||
|
||||
public boolean validateConceptMap(List<ValidationMessage> errors, Element cm, NodeStack stack, ValidationOptions options) {
|
||||
public boolean validateConceptMap(ValidationContext valContext, List<ValidationMessage> errors, Element cm, NodeStack stack, ValidationOptions options) {
|
||||
boolean ok = true;
|
||||
Map<String, PropertyDefinition> props = new HashMap<>();
|
||||
Map<String, String> attribs = new HashMap<>();
|
||||
|
@ -147,7 +150,7 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
List<Element> groups = cm.getChildrenByName("group");
|
||||
int ci = 0;
|
||||
for (Element group : groups) {
|
||||
ok = validateGroup(errors, group, stack.push(group, ci, null, null), props, attribs, options, sourceScope, targetScope) && ok;
|
||||
ok = validateGroup(valContext, errors, group, stack.push(group, ci, null, null), props, attribs, options, sourceScope, targetScope) && ok;
|
||||
ci++;
|
||||
}
|
||||
|
||||
|
@ -213,7 +216,7 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
return null;
|
||||
}
|
||||
|
||||
private boolean validateGroup(List<ValidationMessage> errors, Element grp, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, VSReference sourceScope, VSReference targetScope) {
|
||||
private boolean validateGroup(ValidationContext valContext, List<ValidationMessage> errors, Element grp, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, VSReference sourceScope, VSReference targetScope) {
|
||||
boolean ok = true;
|
||||
GroupContext ctxt = new GroupContext();
|
||||
ctxt.sourceScope = sourceScope;
|
||||
|
@ -229,6 +232,11 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
} else {
|
||||
warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), sourceScope != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_UNKNOWN, e.getValue());
|
||||
}
|
||||
if (ctxt.source.version == null && ctxt.source.cs != null) {
|
||||
Set<String> possibleVersions = fetcher.fetchCanonicalResourceVersions(null, valContext.getAppContext(), ctxt.source.url);
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, grp.line(), grp.col(), stack.getLiteralPath(), possibleVersions.size() <= 1, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS,
|
||||
ctxt.source.url, ctxt.source.cs.getVersion(), CommaSeparatedStringBuilder.join(", ", Utilities.sorted(possibleVersions)));
|
||||
}
|
||||
}
|
||||
e = grp.getNamedChild("target", false);
|
||||
if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_MISSING)) {
|
||||
|
@ -241,6 +249,11 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), targetScope != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_UNKNOWN, e.getValue());
|
||||
|
||||
}
|
||||
if (ctxt.target.version == null && ctxt.target.cs != null) {
|
||||
Set<String> possibleVersions = fetcher.fetchCanonicalResourceVersions(null, valContext.getAppContext(), ctxt.target.url);
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, grp.line(), grp.col(), stack.getLiteralPath(), possibleVersions.size() <= 1, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS,
|
||||
ctxt.target.url, ctxt.target.cs.getVersion(), CommaSeparatedStringBuilder.join(", ", Utilities.sorted(possibleVersions)));
|
||||
}
|
||||
}
|
||||
List<Element> elements = grp.getChildrenByName("element");
|
||||
int ci = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hl7.fhir.validation.instance.type;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
@ -11,6 +12,7 @@ import org.hl7.fhir.r5.model.ValueSet;
|
|||
import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
|
@ -23,6 +25,7 @@ import org.hl7.fhir.validation.codesystem.GeneralCodeSystemChecker;
|
|||
import org.hl7.fhir.validation.codesystem.SnomedCTChecker;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||
|
||||
public class ValueSetValidator extends BaseValidator {
|
||||
|
||||
|
@ -57,13 +60,13 @@ public class ValueSetValidator extends BaseValidator {
|
|||
super(parent);
|
||||
}
|
||||
|
||||
public boolean validateValueSet(List<ValidationMessage> errors, Element vs, NodeStack stack) {
|
||||
public boolean validateValueSet(ValidationContext valContext, List<ValidationMessage> errors, Element vs, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
if (!VersionUtilities.isR2Ver(context.getVersion())) {
|
||||
List<Element> composes = vs.getChildrenByName("compose");
|
||||
int cc = 0;
|
||||
for (Element compose : composes) {
|
||||
ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url", false), "retired".equals(vs.getNamedChildValue("url", false)), vs) & ok;
|
||||
ok = validateValueSetCompose(valContext, errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url", false), "retired".equals(vs.getNamedChildValue("url", false)), vs) & ok;
|
||||
cc++;
|
||||
}
|
||||
}
|
||||
|
@ -99,24 +102,24 @@ public class ValueSetValidator extends BaseValidator {
|
|||
}
|
||||
|
||||
|
||||
private boolean validateValueSetCompose(List<ValidationMessage> errors, Element compose, NodeStack stack, String vsid, boolean retired, Element vsSrc) {
|
||||
private boolean validateValueSetCompose(ValidationContext valContext, List<ValidationMessage> errors, Element compose, NodeStack stack, String vsid, boolean retired, Element vsSrc) {
|
||||
boolean ok = true;
|
||||
List<Element> includes = compose.getChildrenByName("include");
|
||||
int ci = 0;
|
||||
for (Element include : includes) {
|
||||
ok = validateValueSetInclude(errors, include, stack.push(include, ci, null, null), vsid, retired, vsSrc) && ok;
|
||||
ok = validateValueSetInclude(valContext, errors, include, stack.push(include, ci, null, null), vsid, retired, vsSrc) && ok;
|
||||
ci++;
|
||||
}
|
||||
List<Element> excludes = compose.getChildrenByName("exclude");
|
||||
int ce = 0;
|
||||
for (Element exclude : excludes) {
|
||||
ok = validateValueSetInclude(errors, exclude, stack.push(exclude, ce, null, null), vsid, retired, vsSrc) && ok;
|
||||
ok = validateValueSetInclude(valContext, errors, exclude, stack.push(exclude, ce, null, null), vsid, retired, vsSrc) && ok;
|
||||
ce++;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateValueSetInclude(List<ValidationMessage> errors, Element include, NodeStack stack, String vsid, boolean retired, Element vsSrc) {
|
||||
private boolean validateValueSetInclude(ValidationContext valContext, List<ValidationMessage> errors, Element include, NodeStack stack, String vsid, boolean retired, Element vsSrc) {
|
||||
boolean ok = true;
|
||||
String system = include.getChildValue("system");
|
||||
String version = include.getChildValue("version");
|
||||
|
@ -163,6 +166,14 @@ public class ValueSetValidator extends BaseValidator {
|
|||
ok = rule(errors, "2024-02-10", IssueType.INVALID, stack.getLiteralPath(), cs.size() == 1, version == null ? I18nConstants.VALUESET_INCLUDE_CS_MULTI_FOUND : I18nConstants.VALUESET_INCLUDE_CSVER_MULTI_FOUND, system, version) && ok;
|
||||
}
|
||||
}
|
||||
if (version == null) {
|
||||
CodeSystem cs = context.fetchCodeSystem(system);
|
||||
if (cs != null) {
|
||||
Set<String> possibleVersions = fetcher.fetchCanonicalResourceVersions(null, valContext.getAppContext(), system);
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, include.line(), include.col(), stack.getLiteralPath(), possibleVersions.size() <= 1, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_MULTIPLE_POSSIBLE_VERSIONS,
|
||||
system, cs.getVersion(), CommaSeparatedStringBuilder.join(", ", Utilities.sorted(possibleVersions)));
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Element> concepts = include.getChildrenByName("concept");
|
||||
List<Element> filters = include.getChildrenByName("filter");
|
||||
|
|
|
@ -449,7 +449,7 @@ public class R4R5MapTester implements IValidatorResourceFetcher {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) throws URISyntaxException {
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, Object appContext, String url) throws URISyntaxException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -458,4 +458,9 @@ public class R4R5MapTester implements IValidatorResourceFetcher {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
@ -832,7 +834,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
}
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, String url) {
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator validator, Object appContext, String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -867,4 +869,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
StructureDefinition structure, ElementDefinition element, String path) {
|
||||
return EnumSet.allOf(ElementValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue