From cf95c1a2ba525e42dce910d6f1fbccba8d80e9b7 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 18 Mar 2022 12:45:40 +1100 Subject: [PATCH] Fix for Jira 25179 - change handling of imports See https://chat.fhir.org/#narrow/stream/179202-terminology/topic/ValueSet.20defined.20by.20an.20intersection.20.3F --- .../r5/context/CanonicalResourceManager.java | 5 +++ .../hl7/fhir/r5/context/IWorkerContext.java | 17 +++++++--- .../fhir/r5/context/SimpleWorkerContext.java | 4 +-- .../terminologies/ValueSetCheckerSimple.java | 28 ++++++++++++++-- .../terminologies/ValueSetExpanderSimple.java | 32 ++++++++++++++----- .../test/CanonicalResourceManagerTests.java | 7 ++-- .../fhir/utilities/i18n/I18nConstants.java | 1 + .../hl7/fhir/utilities/npm/NpmPackage.java | 25 +++++++++++++++ .../src/main/resources/Messages.properties | 2 ++ .../hl7/fhir/validation/ValidationEngine.java | 2 +- .../instance/InstanceValidator.java | 11 +++++++ .../instance/type/ValueSetValidator.java | 3 ++ .../4.0.1/http___www.ada.org_snodent.cache | 12 +++++++ 13 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 org.hl7.fhir.validation/src/test/resources/txCache/4.0.1/http___www.ada.org_snodent.cache diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java index 34da6eb7a..16826b997 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java @@ -130,6 +130,7 @@ public class CanonicalResourceManager { synchronized (this) { resource = res; } + resource.setUserData("package", packageInfo); proxy = null; } return resource; @@ -226,6 +227,10 @@ public class CanonicalResourceManager { drop(cr.getId()); } + if (cr.resource != null) { + cr.resource.setUserData("package", cr.getPackageInfo()); + } + // special case logic for UTG support prior to version 5 if (cr.getPackageInfo() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology")) { List> toDrop = new ArrayList<>(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 242856766..5ec564013 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -3,6 +3,7 @@ package org.hl7.fhir.r5.context; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Date; /* Copyright (c) 2011+, HL7, Inc. @@ -148,8 +149,9 @@ public interface IWorkerContext { public class PackageVersion { private String id; private String version; + private Date date; - public PackageVersion(String source) { + public PackageVersion(String source, Date date) { if (source == null) { throw new Error("Source cannot be null"); } @@ -158,12 +160,15 @@ public interface IWorkerContext { } id = source.substring(0, source.indexOf("#")); version = source.substring(source.indexOf("#")+1); + this.date = date; } - public PackageVersion(String id, String version) { + public PackageVersion(String id, String version, Date date) { super(); this.id = id; this.version = version; + this.date = date; } + public String getId() { return id; } @@ -178,6 +183,9 @@ public interface IWorkerContext { public String toString() { return id+"#"+version; } + public Date getDate() { + return date; + } } @@ -185,8 +193,9 @@ public interface IWorkerContext { private String name; private String canonical; private String web; - public PackageDetails(String id, String version, String name, String canonical, String web) { - super(id, version); + + public PackageDetails(String id, String version, String name, String canonical, String web, Date date) { + super(id, version, date); this.name = name; this.canonical = canonical; this.web = web; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 239b43c25..fd47242c6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -474,7 +474,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } for (String s : pi.listResources(types)) { try { - loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageVersion(pi.id(), pi.version())); + loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageVersion(pi.id(), pi.version(), pi.dateAsDate())); t++; } catch (Exception e) { throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e); @@ -486,7 +486,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } for (PackageResourceInformation pri : pi.listIndexedResources(types)) { try { - registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version())); + registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version(), pi.dateAsDate())); t++; } catch (FHIRException e) { throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index aeb491319..3472559a6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -32,6 +32,8 @@ package org.hl7.fhir.r5.terminologies; import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -41,6 +43,8 @@ import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.NoTerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.context.IWorkerContext.PackageDetails; +import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CodeSystem; @@ -64,6 +68,7 @@ import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationConte import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.PackageInfo; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode; @@ -671,9 +676,17 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe } private Boolean inComponent(ConceptSetComponent vsi, int vsiIndex, String system, String code, boolean only, List warnings) throws FHIRException { - for (UriType uri : vsi.getValueSet()) { - if (inImport(uri.getValue(), system, code)) { - return true; + if (isValueSetUnionImports()) { + for (UriType uri : vsi.getValueSet()) { + if (inImport(uri.getValue(), system, code)) { + return true; + } + } + } else { + for (UriType uri : vsi.getValueSet()) { + if (!inImport(uri.getValue(), system, code)) { + return false; + } } } @@ -738,6 +751,15 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe } } + protected boolean isValueSetUnionImports() { + PackageVersion p = (PackageVersion) valueset.getUserData("package"); + if (p != null) { + return p.getDate().before(new GregorianCalendar(2022, Calendar.MARCH, 31).getTime()); + } else { + return false; + } + } + private boolean codeInFilter(CodeSystem cs, String system, ConceptSetFilterComponent f, String code) throws FHIRException { if ("concept".equals(f.getProperty())) return codeInConceptFilter(cs, f, code); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java index 1bfe96ff6..20733db59 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java @@ -66,7 +66,9 @@ import java.io.IOException; */ import java.util.ArrayList; +import java.util.Calendar; import java.util.Collection; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -79,6 +81,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.NoTerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode; @@ -426,8 +429,9 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx focus.getExpansion().addParameter().setName(p.getName()).setValue(p.getValue()); } - if (source.hasCompose()) - handleCompose(source.getCompose(), focus.getExpansion(), expParams, source.getUrl(), focus.getExpansion().getExtension()); + if (source.hasCompose()) { + handleCompose(source.getCompose(), focus.getExpansion(), expParams, source.getUrl(), focus.getExpansion().getExtension(), source); + } if (canBeHeirarchy) { for (ValueSetExpansionContainsComponent c : roots) { @@ -467,7 +471,7 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx return null; } - private void handleCompose(ValueSetComposeComponent compose, ValueSetExpansionComponent exp, Parameters expParams, String ctxt, List extensions) + private void handleCompose(ValueSetComposeComponent compose, ValueSetExpansionComponent exp, Parameters expParams, String ctxt, List extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException { compose.checkNoModifiers("ValueSet.compose", "expanding"); // Exclude comes first because we build up a map of things to exclude @@ -481,11 +485,11 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx first = false; else canBeHeirarchy = false; - includeCodes(inc, exp, expParams, canBeHeirarchy, compose.hasInactive() && !compose.getInactive(), extensions); + includeCodes(inc, exp, expParams, canBeHeirarchy, compose.hasInactive() && !compose.getInactive(), extensions, valueSet); } } - private ValueSet importValueSet(String value, ValueSetExpansionComponent exp, Parameters expParams, boolean noInactive) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError { + private ValueSet importValueSet(String value, ValueSetExpansionComponent exp, Parameters expParams, boolean noInactive, ValueSet valueSet) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError { if (value == null) throw fail("unable to find value set with no identity"); ValueSet vs = context.fetchResource(ValueSet.class, value); @@ -521,10 +525,22 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx if (!existsInParams(exp.getParameter(), p.getName(), p.getValue())) exp.getParameter().add(p); } - copyExpansion(vso.getValueset().getExpansion().getContains()); + if (isValueSetUnionImports(valueSet)) { + copyExpansion(vso.getValueset().getExpansion().getContains()); + } canBeHeirarchy = false; // if we're importing a value set, we have to be combining, so we won't try for a heirarchy return vso.getValueset(); } + + + protected boolean isValueSetUnionImports(ValueSet valueSet) { + PackageVersion p = (PackageVersion) valueSet.getUserData("package"); + if (p != null) { + return p.getDate().before(new GregorianCalendar(2022, Calendar.MARCH, 31).getTime()); + } else { + return false; + } + } public void copyExpansion(List list) { for (ValueSetExpansionContainsComponent cc : list) { @@ -562,11 +578,11 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx } } - private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List extensions) throws ETooCostly, FileNotFoundException, IOException, FHIRException { + private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException { inc.checkNoModifiers("Compose.include", "expanding"); List imports = new ArrayList(); for (UriType imp : inc.getValueSet()) { - imports.add(importValueSet(imp.getValue(), exp, expParams, noInactive)); + imports.add(importValueSet(imp.getValue(), exp, expParams, noInactive, valueSet)); } if (!inc.hasSystem()) { diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java index 1e9d18d46..3829e7d07 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java @@ -1,5 +1,7 @@ package org.hl7.fhir.r5.test; +import java.util.Date; + import org.hl7.fhir.r5.context.CanonicalResourceManager; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; @@ -425,14 +427,13 @@ public class CanonicalResourceManagerTests { vs2.setUrl("http://terminology.hl7.org/ValueSet/234"); vs2.setVersion("2000.0.0"); vs2.setName("2"); - - mrm.see(vs1, new PackageVersion("hl7.fhir.r4.core", "4.0.1")); + mrm.see(vs1, new PackageVersion("hl7.fhir.r4.core", "4.0.1", new Date())); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234")); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234", "2.0.0")); Assertions.assertTrue(mrm.get("http://terminology.hl7.org/ValueSet/234").getName().equals("1")); - mrm.see(vs2, new PackageVersion("hl7.terminology.r4", "4.0.1")); + mrm.see(vs2, new PackageVersion("hl7.terminology.r4", "4.0.1", new Date())); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234")); Assertions.assertTrue(mrm.get("http://terminology.hl7.org/ValueSet/234").getName().equals("2")); Assertions.assertNull(mrm.get("http://terminology.hl7.org/ValueSet/234", "2.0.0")); // this will get dropped completely because of UTG rules diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index a3d1cf554..366dea8b8 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -622,6 +622,7 @@ public class I18nConstants { public static final String VALUESET_REFERENCE_UNKNOWN = "VALUESET_REFERENCE_UNKNOWN"; public static final String VALUESET_UNC_SYSTEM_WARNING = "VALUESET_UNC_SYSTEM_WARNING"; public static final String VALUESET_UNC_SYSTEM_WARNING_VER = "VALUESET_UNC_SYSTEM_WARNING_VER"; + public static final String VALUESET_IMPORT_UNION_INTERSECTION = "VALUESET_IMPORT_UNION_INTERSECTION"; public static final String VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_ = "Version_mismatch_The_context_has_version__loaded_and_the_new_content_being_loaded_is_version_"; public static final String WRONG_NAMESPACE__EXPECTED_ = "Wrong_namespace__expected_"; public static final String WRONG_TYPE_FOR_RESOURCE = "Wrong_type_for_resource"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index 9cbeb5aac..96c3bc346 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -42,9 +42,12 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1134,6 +1137,28 @@ public class NpmPackage { public InputStream load(PackageResourceInformation p) throws FileNotFoundException { return new FileInputStream(p.filename); } + + public Date dateAsDate() { + try { + String d = date(); + if (d == null) { + switch (name()) { + case "hl7.fhir.r2.core": d = "20151024000000"; break; + case "hl7.fhir.r2b.core": d = "20160330000000"; break; + case "hl7.fhir.r3.core": d = "20191024000000"; break; + case "hl7.fhir.r4.core": d = "20191030000000"; break; + case "hl7.fhir.r4b.core": d = "202112200000000"; break; + case "hl7.fhir.r5.core": d = "20211219000000"; break; + default: + return new Date(); + } + } + return new SimpleDateFormat("yyyyMMddHHmmss").parse(d); + } catch (ParseException e) { + // this really really shouldn't happen + return new Date(); + } + } } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index fa1748615..2d6096cfd 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -706,3 +706,5 @@ TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG_UCUM = The value in the instance ({0 TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR = Base64 encoded values are not allowed to contain any whitespace (per RFC 4648). Note that non-validating readers are encouraged to accept whitespace anyway TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING = Base64 encoded values SHOULD not contain any whitespace (per RFC 4648). Note that non-validating readers are encouraged to accept whitespace anyway SD_DERIVATION_KIND_MISMATCH = The structure definition constrains a kind of {0}, but has a different kind ({1}) +VALUESET_IMPORT_UNION_INTERSECTION = This value set has an include with multiple imported value sets. Per issue https://jira.hl7.org/browse/FHIR-25179, there has been confusion in the past whether these value sets are unioned or intersectioned. If this value set is contained in a package published prior to March 31 2022, it will be treated as a union, otherwise it will be treated as an intersection + \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 3885c3c36..13ced41da 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -280,7 +280,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (userAgent != null) { contextBuilder.withUserAgent(userAgent); } - context = contextBuilder.fromDefinitions(source, ValidatorUtils.loaderForVersion(version), new PackageVersion(src)); + context = contextBuilder.fromDefinitions(source, ValidatorUtils.loaderForVersion(version), new PackageVersion(src, new Date())); ValidatorUtils.grabNatives(getBinaries(), source, "http://hl7.org/fhir"); } // ucum-essence.xml should be in the class path. if it's not, ask about how to sort this out diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 3e94b0f9d..bfdd3c27d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -5757,6 +5757,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return "htmlChecks2()"; } + // clarification in FHIRPath spec + if (expr.equals("name.matches('[A-Z]([A-Za-z0-9_]){0,254}')")) { + return "name.matches('^[A-Z]([A-Za-z0-9_]){0,254}$')"; + } + if ("eld-19".equals(key)) { + return "path.matches('^[^\\\\s\\\\.,:;\\\\\\'\"\\\\/|?!@#$%&*()\\\\[\\\\]{}]{1,64}(\\\\.[^\\\\s\\\\.,:;\\\\\\'\"\\\\/|?!@#$%&*()\\\\[\\\\]{}]{1,64}(\\\\[x\\\\])?(\\\\:[^\\\\s\\\\.]+)?)*$')"; + } + if ("eld-20".equals(key)) { + return "path.matches('^[A-Za-z][A-Za-z0-9]*(\\\\.[a-z][A-Za-z0-9]*(\\\\[x])?)*$')"; + } + // handled in 4.0.1 if ("(component.empty() and hasMember.empty()) implies (dataAbsentReason or value)".equals(expr)) { return "(component.empty() and hasMember.empty()) implies (dataAbsentReason.exists() or value.exists())"; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index 773f93485..88aed13fd 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -98,6 +98,9 @@ public class ValueSetValidator extends BaseValidator { } i++; } + if (valuesets.size() > 1) { + warning(errors, IssueType.INFORMATIONAL, stack.getLiteralPath(), false, I18nConstants.VALUESET_IMPORT_UNION_INTERSECTION); + } List concepts = include.getChildrenByName("concept"); List filters = include.getChildrenByName("filter"); if (!Utilities.noString(system)) { diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/4.0.1/http___www.ada.org_snodent.cache b/org.hl7.fhir.validation/src/test/resources/txCache/4.0.1/http___www.ada.org_snodent.cache new file mode 100644 index 000000000..d5350b2dc --- /dev/null +++ b/org.hl7.fhir.validation/src/test/resources/txCache/4.0.1/http___www.ada.org_snodent.cache @@ -0,0 +1,12 @@ +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://www.ada.org/snodent", + "code" : "210965D", + "display" : "Anterior part of lower alveolar ridge" +}, "valueSet" :null, "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}#### +v: { + "display" : "Anterior part of lower alveolar ridge", + "code" : "210965D", + "system" : "http://www.ada.org/snodent" +} +-------------------------------------------------------------------------------------