From de15633f4ffb337d833b48d45f3408540c65596a Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 18 Nov 2021 10:59:49 +1100 Subject: [PATCH] Address issues around fragment and example code systems + fix value set related validation messages --- .../fhir/r5/context/BaseWorkerContext.java | 15 +++- .../hl7/fhir/r5/context/IWorkerContext.java | 8 ++ .../hl7/fhir/r5/model/CanonicalResource.java | 6 +- .../fhir/r5/renderers/CodeSystemRenderer.java | 2 +- .../fhir/r5/renderers/ValueSetRenderer.java | 57 +++++++++---- .../r5/terminologies/CodeSystemUtilities.java | 9 ++ .../terminologies/ValueSetExpanderSimple.java | 24 +++++- .../hl7/fhir/r5/utils/ToolingExtensions.java | 1 - .../fhir/utilities/i18n/I18nConstants.java | 6 ++ .../src/main/resources/Messages.properties | 35 +++++--- .../src/main/resources/Messages_de.properties | 22 ++--- .../src/main/resources/Messages_nl.properties | 26 +++--- .../instance/InstanceValidator.java | 45 ++++++---- .../instance/type/BundleValidator.java | 10 +-- .../instance/type/CodeSystemValidator.java | 85 +++++++++++++++++-- 15 files changed, 259 insertions(+), 92 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index f441447a4..2a4084b60 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -643,10 +643,18 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte if (expParameters == null) throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED)); Parameters p = expParameters.copy(); - return expandVS(vs, cacheOk, heirarchical, p); + return expandVS(vs, cacheOk, heirarchical, false, p); } - public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, Parameters p) { + @Override + public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, boolean incompleteOk) { + if (expParameters == null) + throw new Error(formatMessage(I18nConstants.NO_EXPANSION_PARAMETERS_PROVIDED)); + Parameters p = expParameters.copy(); + return expandVS(vs, cacheOk, heirarchical, incompleteOk, p); + } + + public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical, boolean incompleteOk, Parameters p) { if (p == null) { throw new Error(formatMessage(I18nConstants.NO_PARAMETERS_PROVIDED_TO_EXPANDVS)); } @@ -673,6 +681,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } p.setParameter("includeDefinition", false); p.setParameter("excludeNested", !heirarchical); + if (incompleteOk) { + p.setParameter("incomplete-ok", true); + } List allErrors = 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 6dd535d95..d5067a941 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 @@ -508,6 +508,14 @@ public interface IWorkerContext { */ public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical); + /** + * ValueSet Expansion - see $expand + * + * @param source + * @return + */ + public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical, boolean incompleteOk); + /** * ValueSet Expansion - see $expand, but resolves the binding first * diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java index 207dc68f8..16c5bbd07 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java @@ -553,7 +553,11 @@ public abstract class CanonicalResource extends DomainResource { public boolean supportsCopyright() { return true; } - + + public String getVersionedUrl() { + return hasVersion() ? getUrl()+"|"+getVersion() : getUrl(); + } + // end addition } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index f9618e79f..5f729aad8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -126,7 +126,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { if (cs.getContent() == CodeSystemContentMode.COMPLETE) p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":"); else if (cs.getContent() == CodeSystemContentMode.EXAMPLE) - p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are some examples", cs.getUrl())+":"); + p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines some example codes", cs.getUrl())+":"); else if (cs.getContent() == CodeSystemContentMode.FRAGMENT ) p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":"); else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java index 507b67db8..e88e85122 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java @@ -176,23 +176,8 @@ public class ValueSetRenderer extends TerminologyRenderer { else x.para().tx("This value set contains "+count.toString()+" concepts"); } - if (ToolingExtensions.hasExtension(vs.getExpansion(), ToolingExtensions.EXT_EXP_FRAGMENT)) { - XhtmlNode div = x.div().style("border: maroon 1px solid; background-color: #FFCCCC; padding: 8px"); - List exl = vs.getExpansion().getExtensionsByUrl(ToolingExtensions.EXT_EXP_FRAGMENT); - if (exl.size() > 1) { - div.para().addText("Warning: this expansion is generated from fragments of the following code systems, and may be missing codes, or include codes that are not valid:"); - XhtmlNode ul = div.ul(); - for (Extension ex : exl) { - addCSRef(ul.li(), ex.getValue().primitiveValue()); - } - } else { - XhtmlNode p = div.para(); - p.addText("Warning: this expansion is generated from a fragment of the code system "); - addCSRef(p, exl.get(0).getValue().primitiveValue()); - p.addText(" and may be missing codes, or include codes that are not valid"); - } - } + generateContentModeNotices(x, vs.getExpansion()); generateVersionNotice(x, vs.getExpansion()); CodeSystem allCS = null; @@ -273,6 +258,46 @@ public class ValueSetRenderer extends TerminologyRenderer { return hasExtensions; } + private void generateContentModeNotices(XhtmlNode x, ValueSetExpansionComponent expansion) { + generateContentModeNotice(x, expansion, "example", "Expansion based on example code system"); + generateContentModeNotice(x, expansion, "fragment", "Expansion based on code system fragment"); + } + + private void generateContentModeNotice(XhtmlNode x, ValueSetExpansionComponent expansion, String mode, String text) { + Multimap versions = HashMultimap.create(); + for (ValueSetExpansionParameterComponent p : expansion.getParameter()) { + if (p.getName().equals(mode)) { + String[] parts = ((PrimitiveType) p.getValue()).asStringValue().split("\\|"); + if (parts.length == 2) + versions.put(parts[0], parts[1]); + } + } + if (versions.size() > 0) { + XhtmlNode div = null; + XhtmlNode ul = null; + boolean first = true; + for (String s : versions.keySet()) { + if (versions.size() == 1 && versions.get(s).size() == 1) { + for (String v : versions.get(s)) { // though there'll only be one + XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #ffcccc; padding: 8px; margin-bottom: 8px"); + p.tx(text+" "); + expRef(p, s, v); + } + } else { + for (String v : versions.get(s)) { + if (first) { + div = x.div().style("border: black 1px dotted; background-color: #EEEEEE; padding: 8px; margin-bottom: 8px"); + div.para().tx(text+"s: "); + ul = div.ul(); + first = false; + } + expRef(ul.li(), s, v); + } + } + } + } + } + private boolean checkDoSystem(ValueSet vs, ValueSet src) { if (src != null) vs = src; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java index 6fcb1ac8b..02815b115 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java @@ -490,5 +490,14 @@ public class CodeSystemUtilities { } } + + public static boolean hasHierarchy(CodeSystem cs) { + for (ConceptDefinitionComponent c : cs.getConcept()) { + if (c.hasConcept()) { + return true; + } + } + return false; + } } \ No newline at end of file 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 382c10419..bd45f5cac 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 @@ -634,6 +634,9 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { addFragmentWarning(exp, cs); } + if (cs.getContent() == CodeSystemContentMode.EXAMPLE) { + addExampleWarning(exp, cs); + } } if (!inc.getConcept().isEmpty()) { @@ -645,6 +648,8 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx if (def == null) { if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { addFragmentWarning(exp, cs); + } else if (cs.getContent() == CodeSystemContentMode.EXAMPLE) { + addExampleWarning(exp, cs); } else { if (checkCodesWhenExpanding) { throw failTSE("Unable to find code '" + c.getCode() + "' in code system " + cs.getUrl()); @@ -733,14 +738,25 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx } private void addFragmentWarning(ValueSetExpansionComponent exp, CodeSystem cs) { - for (Extension ex : cs.getExtensionsByUrl(ToolingExtensions.EXT_EXP_FRAGMENT)) { - if (ex.getValue().primitiveValue().equals(cs.getUrl())) { + String url = cs.getVersionedUrl(); + for (ValueSetExpansionParameterComponent p : exp.getParameter()) { + if ("fragment".equals(p.getName()) && p.hasValueUriType() && url.equals(p.getValue().primitiveValue())) { return; - } + } } - exp.addExtension(new Extension(ToolingExtensions.EXT_EXP_FRAGMENT).setValue(new UriType(cs.getUrl()))); + exp.addParameter().setName("fragment").setValue(new UriType(url)); } + private void addExampleWarning(ValueSetExpansionComponent exp, CodeSystem cs) { + String url = cs.getVersionedUrl(); + for (ValueSetExpansionParameterComponent p : exp.getParameter()) { + if ("example".equals(p.getName()) && p.hasValueUriType() && url.equals(p.getValue().primitiveValue())) { + return; + } + } + exp.addParameter().setName("example").setValue(new UriType(url)); + } + private List convertDesignations(List list) { List res = new ArrayList(); for (ConceptReferenceDesignationComponent t : list) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index e9311f488..a107dfc26 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -183,7 +183,6 @@ public class ToolingExtensions { public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type"; public static final String EXT_RENDERED_VALUE = "http://hl7.org/fhir/StructureDefinition/rendered-value"; public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence"; - public static final String EXT_EXP_FRAGMENT = "http://hl7.org/fhir/tools/StructureDefinition/expansion-codesystem-fragment"; public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"; public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support"; public static final String EXT_TRANSLATABLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-translatable"; 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 acf93ba56..acb5a6953 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 @@ -652,6 +652,12 @@ public class I18nConstants { public static final String BUNDLE_SEARCH_ENTRY_WRONG_RESOURCE_TYPE_OUTCOME = "BUNDLE_SEARCH_ENTRY_WRONG_RESOURCE_TYPE_OUTCOME"; public static final String UNICODE_BIDI_CONTROLS_CHARS_DISALLOWED = "UNICODE_BIDI_CONTROLS_CHARS_DISALLOWED"; public static final String UNICODE_BIDI_CONTROLS_CHARS_MATCH = "UNICODE_BIDI_CONTROLS_CHARS_MATCH"; + public static final String CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHALL = "CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHALL"; + public static final String CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD = "CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD"; + public static final String CODESYSTEM_CS_NONHL7_MISSING_ELEMENT = "CODESYSTEM_CS_NONHL7_MISSING_ELEMENT"; + public static final String CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL = "CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL"; + public static final String CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG = "CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG"; + public static final String CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING = "CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 62ed6989e..1533ce4ea 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -132,10 +132,10 @@ Terminology_TX_Binding_NoSource = Binding for path {0} has no source, so can''t Terminology_TX_Binding_NoSource2 = Binding has no source, so can''t be checked Terminology_TX_Code_NotValid = Code {0} is not a valid code in code system {1} Terminology_TX_Code_Unknown = Unknown Code ({0}#{1}) -Terminology_TX_Code_ValueSet = No code provided, and a code is required from the value set {0} ({1}) +Terminology_TX_Code_ValueSet = No code provided, and a code is required from the value set {0} Terminology_TX_Code_ValueSet_MISSING = No code provided, and a code is required from the value set Terminology_TX_Code_ValueSetMax = No code provided, and a code must be provided from the value set {0} (max value set {1}) -Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} ({1}) +Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements Terminology_TX_Confirm_1_CC = Could not confirm that the codings provided are in the value set {0} and a coding from this value set is required (class = {1}) Terminology_TX_Confirm_2_CC = Could not confirm that the codings provided are in the value set {0} and a coding should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1}) @@ -149,24 +149,24 @@ Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept Terminology_TX_Error_CodeableConcept_Max = Error {0} validating CodeableConcept using maxValueSet Terminology_TX_Error_Coding1 = Error {0} validating Coding Terminology_TX_Error_Coding2 = Error {0} validating Coding: {1} -Terminology_TX_NoValid_1_CC = None of the codings provided are in the value set {0} ({1}), and a coding from this value set is required) (codes = {2}) -Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3}) -Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2}) +Terminology_TX_NoValid_1_CC = None of the codings provided are in the value set {0}, and a coding from this value set is required) (codes = {1}) +Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0}, and a code from this value set is required) (code = {1}#{2}) +Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0}, and a code from this value set is required) (code = {1}#{2}), error = {3}) Terminology_TX_NoValid_12 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set. {1} Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable). {1} Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1} Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server -Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is required from this value set){3} -Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) {3} -Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3} -Terminology_TX_NoValid_2_CC = None of the codings provided are in the value set {0} ({1}), and a coding should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) (codes = {2}) -Terminology_TX_NoValid_3_CC = None of the codings provided are in the value set {0} ({1}), and a coding is recommended to come from this value set) (codes = {2}) +Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1}, and a code is required from this value set){2} +Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1}, and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) {2} +Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1}, and a code is recommended to come from this value set){2} +Terminology_TX_NoValid_2_CC = None of the codings provided are in the value set {0}, and a coding should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) (codes = {1}) +Terminology_TX_NoValid_3_CC = None of the codings provided are in the value set {0}, and a coding is recommended to come from this value set) (codes = {1}) Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1} Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) {1} Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1} -Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2}) -Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2}) -Terminology_TX_NoValid_9 = The code provided could not be validated against the maximum value set {0} ({1}), (error = {2}) +Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0}, (error = {2}) +Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0}, and a code from this value set is required) (codes = {1}) +Terminology_TX_NoValid_9 = The code provided could not be validated against the maximum value set {0}, (error = {1}) Terminology_TX_System_Invalid = Invalid System URI: {0} Terminology_TX_System_NotKnown = Code System URI ''{0}'' is unknown so the code cannot be validated Terminology_TX_System_Relative = Coding.system must be an absolute reference, not a local reference @@ -662,4 +662,11 @@ INV_FAILED = Rule {0} Failed PATTERN_CHECK_STRING = The pattern [{0}] defined in the profile {1} not found. Issues: {2} TYPE_SPECIFIC_CHECKS_DT_URL_EXAMPLE = Example URLs are not allowed in this context ({0}) UNICODE_BIDI_CONTROLS_CHARS_DISALLOWED = The Unicode sequence has bi-di control characters which are not allowed in this context: {1} -UNICODE_BIDI_CONTROLS_CHARS_MATCH = The Unicode sequence has unterminated bi-di control characters (see CVE-2021-42574): {1} +UNICODE_BIDI_CONTROLS_CHARS_MATCH = The Unicode sequence has unterminated bi-di control characters (see CVE-2021-42574): {1} +CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHALL = HL7 Defined CodeSystems SHALL have a stated value for the {0} element so that users know the status and meaning of the code system clearly +CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD = HL7 Defined CodeSystems SHOULD have a stated value for the {0} element so that users know the status and meaning of the code system clearly +CODESYSTEM_CS_NONHL7_MISSING_ELEMENT = CodeSystems SHOULD have a stated value for the {0} element so that users know the status and meaning of the code system clearly +CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL = CodeSystems SHOULD NOT have a stated value for the {0} element when they are a supplement +CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG = CodeSystem Supplements SHALL have a content value of 'supplement' +CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING = CodeSystem Supplements with a content value of 'supplement' SHALL have a supplements elemnet that specifies which code system is being supplemented + diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages_de.properties b/org.hl7.fhir.utilities/src/main/resources/Messages_de.properties index ec09a482c..16c0cc1fe 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages_de.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages_de.properties @@ -143,24 +143,24 @@ Terminology_TX_Error_CodeableConcept=Fehler {0} bei der Validierung des Codeable Terminology_TX_Error_CodeableConcept_Max=Fehler {0} bei der Validierung des CodeableConcepts mit maxValueSet Terminology_TX_Error_Coding1=Fehler {0} bei der Validierung des Coding Terminology_TX_Error_Coding2=Fehler {0} bei der Validierung des Coding: {1} -Terminology_TX_NoValid_1_CC=Keiner der bereitgestellten Codes ist im ValueSet {0} ({1}, und ein Code aus diesem ValueSet ist erforderlich) (Codes = {2}) -Terminology_TX_NoValid_10=Der bereitgestellte Code ist nicht im maximum ValueSet {0} ({1}, und ein Code aus diesem ValueSet ist erforderlich) (Code = {2}#{3}) -Terminology_TX_NoValid_11=Der bereitgestellte Code ist nicht im maximum value set {0} ({1}{2} +Terminology_TX_NoValid_1_CC=Keiner der bereitgestellten Codes ist im ValueSet {0}, und ein Code aus diesem ValueSet ist erforderlich) (Codes = {1}) +Terminology_TX_NoValid_10=Der bereitgestellte Code ist nicht im maximum ValueSet {0}, und ein Code aus diesem ValueSet ist erforderlich) (Code = {1}#{2}) +Terminology_TX_NoValid_11=Der bereitgestellte Code ist nicht im maximum value set {0}, und ein Code aus diesem ValueSet ist erforderlich) (Code = {1}#{2}, Fehler = {3})) Terminology_TX_NoValid_12=Die angegebene Codierung ist nicht im ValueSet {0} enthalten, und es wird ein Code aus diesem ValueSet ben\u00f6tigt. {1} Terminology_TX_NoValid_13=Die bereitgestellte Codierung ist nicht im ValueSet {0} enthalten, und ein Code sollte aus diesem ValueSet stammen, es sei denn, er hat enth\u00e4lt geeigneten Code. {1} Terminology_TX_NoValid_14=Die angegebene Codierung ist nicht im ValueSet {0} enthalten, und es wird empfohlen, einen Code aus diesem ValueSet zu verwenden. {1} Terminology_TX_NoValid_15=Der angegebene Wert ("{0}") konnte in Ermangelung eines Terminologieservers nicht validiert werden. -Terminology_TX_NoValid_16=Der angegebene Wert ("{0}") ist nicht im ValueSet {1} ({2}, und ein Code aus diesem Valueset ist erforderlich){3} -Terminology_TX_NoValid_17=Der angegebene Wert ("{0}") ist nicht im Valueset {1} ({2}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er hat enth\u00e4lt geeigneten Code){3} -Terminology_TX_NoValid_18=Der angegebene Wert ("{0}") ist nicht im Valueset {1} ({2}, und es wird empfohlen, einen Code aus diesem Valueset zu verwenden){3} -Terminology_TX_NoValid_2_CC=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enth\u00e4lt keinen geeigneten Code) (Codes = {2}) -Terminology_TX_NoValid_3_CC=Keiner der angegebenen Codes ist im Valueset {0} ({1}, und es wird empfohlen, einen Code aus dieserm Valueset zu verwenden) (Codes = {2}) +Terminology_TX_NoValid_16=Der angegebene Wert ("{0}") ist nicht im ValueSet {1}, und ein Code aus diesem Valueset ist erforderlich){2} +Terminology_TX_NoValid_17=Der angegebene Wert ("{0}") ist nicht im Valueset {1}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er hat enth\u00e4lt geeigneten Code){2} +Terminology_TX_NoValid_18=Der angegebene Wert ("{0}") ist nicht im Valueset {1}, und es wird empfohlen, einen Code aus diesem Valueset zu verwenden){2} +Terminology_TX_NoValid_2_CC=Keiner der angegebenen Codes ist im Valueset {0}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enth\u00e4lt keinen geeigneten Code) (Codes = {1}) +Terminology_TX_NoValid_3_CC=Keiner der angegebenen Codes ist im Valueset {0}, und es wird empfohlen, einen Code aus dieserm Valueset zu verwenden) (Codes = {1}) Terminology_TX_NoValid_4=Die bereitgestellte Codierung ist nicht im Valueset {0}, und es wird ein Code aus diesem Valueset ben\u00f6tigt{1} Terminology_TX_NoValid_5=Die angegebene Codierung ist nicht im Valueset {0}, und ein Code sollte aus diesem Valueset stammen, es sei denn, er enth\u00e4lt keinen geeigneten Code{1} Terminology_TX_NoValid_6=Die bereitgestellte Codierung ist nicht im Valueset {0} enthalten, und es wird empfohlen, einen Code aus diesem Valueset zu verwenden{1} -Terminology_TX_NoValid_7=Keiner der bereitgestellten Codes konnte gegen das maximum value set {0} ({1}) validiert werden, (Fehler = {2}) -Terminology_TX_NoValid_8=Keiner der bereitgestellten Codes befindet sich im maximum value sete {0} ({1}, und ein Code aus diesem Valueset ist erforderlich) (Codes = {2}) -Terminology_TX_NoValid_9=Der bereitgestellte Code konnte nicht gegen das the maximum value set {0} ({1}) validiert werden, (Fehler = {2}) +Terminology_TX_NoValid_7=Keiner der bereitgestellten Codes konnte gegen das maximum value set {0} validiert werden, (Fehler = {1}) +Terminology_TX_NoValid_8=Keiner der bereitgestellten Codes befindet sich im maximum value sete {0}, und ein Code aus diesem Valueset ist erforderlich) (Codes = {1}) +Terminology_TX_NoValid_9=Der bereitgestellte Code konnte nicht gegen das the maximum value set {0} validiert werden, (Fehler = {1}) Terminology_TX_System_Invalid=Ung\u00fcltige System URI: {0} Terminology_TX_System_NotKnown=Code System URI "{0}" ist unbekannt, so dass der Code nicht validiert werden kann Terminology_TX_System_Relative=Coding.system muss eine absolute Referenz sein, nicht eine lokale Referenz diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages_nl.properties b/org.hl7.fhir.utilities/src/main/resources/Messages_nl.properties index 301e92ded..e720a5f74 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages_nl.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages_nl.properties @@ -130,10 +130,10 @@ Terminology_TX_Binding_NoSource = Binding voor pad {0} heeft geen bron, dus kan Terminology_TX_Binding_NoSource2 = Binding heeft geen bron, dus kan niet worden gevalideerd Terminology_TX_Code_NotValid = Code {0} is geen geldige code in het codesysteem {1} Terminology_TX_Code_Unknown = Onbekende code ({0}#{1}) -Terminology_TX_Code_ValueSet = Geen code aanwezig en een code is verplicht uit waardelijst {0} ({1}) is verplicht +Terminology_TX_Code_ValueSet = Geen code aanwezig en een code is verplicht uit waardelijst {0} is verplicht Terminology_TX_Code_ValueSet_MISSING = Geen code aanwezig en een code is verplicht uit de waardelijst Terminology_TX_Code_ValueSetMax = Geen code aanwezig en een code is verplicht uit de waardelijst {0} (max waardelijst {1}) -Terminology_TX_Code_ValueSet_Ext = Geen code aanwezig en een code is verplicht uit waardelijst {0} ({1}) +Terminology_TX_Code_ValueSet_Ext = Geen code aanwezig en een code is verplicht uit waardelijst {0} Terminology_TX_Coding_Count = Verwacht {0}, maar gevonden {1} coding elementen Terminology_TX_Confirm_1_CC = Kan niet bevestigen dat de gevonden codings bestaan in de waardelijst {0} en een coding uit deze waardelijst is verplicht (class = {1}) Terminology_TX_Confirm_2_CC = Kan niet bevestigen dat de gevonden codings bestaan in de waardelijst {0} en een coding uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) (class = {1}) @@ -147,24 +147,24 @@ Terminology_TX_Error_CodeableConcept = Fout {0} bij valideren CodeableConcept Terminology_TX_Error_CodeableConcept_Max = Fout {0} bij valideren CodeableConcept met maxValueSet Terminology_TX_Error_Coding1 = Fout {0} bij valideren Coding Terminology_TX_Error_Coding2 = Fout {0} bij valideren Coding: {1} -Terminology_TX_NoValid_1_CC = Geen van de gevonden codings bestaan in waardelijst {0} ({1}) en een coding uit deze waardelijst is verplicht (codes = {2}) -Terminology_TX_NoValid_10 = De gevonden code bestaat niet in de maximum waardelijst {0} ({1}) en een code uit deze waardelijst is verplicht (code = {2}#{3}) -Terminology_TX_NoValid_11 = De gevonden code bestaat niet in de maximum waardelijst {0} ({1}{2}) +Terminology_TX_NoValid_1_CC = Geen van de gevonden codings bestaan in waardelijst {0} en een coding uit deze waardelijst is verplicht (codes = {1}) +Terminology_TX_NoValid_10 = De gevonden code bestaat niet in de maximum waardelijst {0} en een code uit deze waardelijst is verplicht (code = {1}#{2}) +Terminology_TX_NoValid_11 = De gevonden code bestaat niet in de maximum waardelijst {0} en een code uit deze waardelijst is verplicht (code = {1}#{2}, fout = {3}) Terminology_TX_NoValid_12 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is verplicht. {1} Terminology_TX_NoValid_13 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) ({1}) Terminology_TX_NoValid_14 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is aanbevolen. {1} Terminology_TX_NoValid_15 = De gevonden waarde (''{0}'') kan niet worden gevalideerd zonder een terminologieserver -Terminology_TX_NoValid_16 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} ({2}) en een code uit deze waardelijst is verplicht {3} -Terminology_TX_NoValid_17 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} ({2}) en een code uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) {3} -Terminology_TX_NoValid_18 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} ({2}) en een code uit deze waardelijst is aanbevolen. {3} -Terminology_TX_NoValid_2_CC = Geen van de gevonden codings bestaat in de waardelijst {0} ({1}) en een coding uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) (codes = {2}) -Terminology_TX_NoValid_3_CC = Geen van de gevonden codings bestaat in de waardelijst {0} ({1}) en een coding uit deze waardelijst is aanbevolen (codes = {2}) +Terminology_TX_NoValid_16 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} en een code uit deze waardelijst is verplicht {2} +Terminology_TX_NoValid_17 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} en een code uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) {2} +Terminology_TX_NoValid_18 = De gevonden waarde (''{0}'') bestaat niet in de waardelijst {1} en een code uit deze waardelijst is aanbevolen. {2} +Terminology_TX_NoValid_2_CC = Geen van de gevonden codings bestaat in de waardelijst {0} en een coding uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) (codes = {1}) +Terminology_TX_NoValid_3_CC = Geen van de gevonden codings bestaat in de waardelijst {0} en een coding uit deze waardelijst is aanbevolen (codes = {1}) Terminology_TX_NoValid_4 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is verplicht {1} Terminology_TX_NoValid_5 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is verplicht tenzij deze geen relevante code bevat (de validator kan niet bepalen wat relevant is) {1} Terminology_TX_NoValid_6 = De gevonden Coding ({2}) bestaat niet in de waardelijst {0} en een code uit deze waardelijst is aanbevolen {1} -Terminology_TX_NoValid_7 = Geen van de gevonden codes kon worden gevalideerd tegen de maximum waardelijst {0} ({1}), (fout = {2}) -Terminology_TX_NoValid_8 = Geen van de gevonden codes bestaan in de maximum waardelijst {0} ({1}) en een code uit deze waardelijst is verplicht (codes = {2}) -Terminology_TX_NoValid_9 = De gevonden code kon niet worden gevalideerd tegen de maximum waardelijst {0} ({1}), (fout = {2}) +Terminology_TX_NoValid_7 = Geen van de gevonden codes kon worden gevalideerd tegen de maximum waardelijst {0}, (fout = {2}) +Terminology_TX_NoValid_8 = Geen van de gevonden codes bestaan in de maximum waardelijst {0} en een code uit deze waardelijst is verplicht (codes = {1}) +Terminology_TX_NoValid_9 = De gevonden code kon niet worden gevalideerd tegen de maximum waardelijst {0}, (fout = {1}) Terminology_TX_System_Invalid = Ongeldige system URI: {0} Terminology_TX_System_NotKnown = CodeSystem URI ''{0}'' is onbekend dus de code kan niet worden gevalideerd Terminology_TX_System_Relative = Coding.system moet een absolute referentie zijn, geen lokale referentie 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 19f479347..3e357a716 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 @@ -1060,12 +1060,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat CodeableConcept cc = ObjectConverter.readAsCodeableConcept(element); if (!cc.hasCoding()) { if (binding.getStrength() == BindingStrength.REQUIRED) - rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeReference(binding.getValueSet()), valueset.getUrl()); + rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeValueSet(binding.getValueSet())); else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")), valueset.getUrl()); else - warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(binding.getValueSet()), valueset.getUrl()); + warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeValueSet(binding.getValueSet())); } } else { long t = System.nanoTime(); @@ -1112,15 +1112,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } else { if (binding.getStrength() == BindingStrength.REQUIRED) { - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); } else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { - txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); } } } @@ -1197,7 +1197,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")), valueset.getUrl()); else - warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(binding.getValueSet()), valueset.getUrl()); + warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeValueSet(binding.getValueSet())); } } else { long t = System.nanoTime(); @@ -1239,15 +1239,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } else { if (binding.getStrength() == BindingStrength.REQUIRED) - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), cc, stack); if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { - txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet()), valueset.getUrl(), ccSummary(cc)); + txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeValueSet(binding.getValueSet()), ccSummary(cc)); } } } @@ -1462,9 +1462,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+cc.toString()); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeReference(maxVSUrl), valueset.getUrl(), vr.getMessage()); + txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeValueSet(maxVSUrl), vr.getMessage()); else - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeReference(maxVSUrl), valueset.getUrl(), ccSummary(cc)); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeValueSet(maxVSUrl), ccSummary(cc)); } } catch (Exception e) { if (STACK_TRACE) e.printStackTrace(); @@ -1473,6 +1473,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } + private String describeValueSet(String url) { + ValueSet vs = context.fetchResource(ValueSet.class, url); + if (vs != null) { + return "\""+vs.present()+"\" ("+url+")"; + } else { + return "("+url+")"; + } + } + private void checkMaxValueSet(List errors, String path, Element element, StructureDefinition profile, String maxVSUrl, Coding c, NodeStack stack) { ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl()); if (valueset == null) { @@ -1487,9 +1496,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl), valueset.getUrl(), vr.getMessage()); + txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeValueSet(maxVSUrl), vr.getMessage()); else - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeReference(maxVSUrl), valueset.getUrl(), c.getSystem(), c.getCode()); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeValueSet(maxVSUrl), c.getSystem(), c.getCode()); } } catch (Exception e) { if (STACK_TRACE) e.printStackTrace(); @@ -1512,9 +1521,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+value); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl), valueset.getUrl(), vr.getMessage()); + txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeValueSet(maxVSUrl), vr.getMessage()); else - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeReference(maxVSUrl), valueset.getUrl(), "), and a code from this value set is required) (code = " + value + "), (error = " + vr.getMessage() + ")"); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeValueSet(maxVSUrl), vr.getMessage()); } } catch (Exception e) { if (STACK_TRACE) e.printStackTrace(); @@ -2555,15 +2564,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (vr.IsNoService()) txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_15, value); else if (binding.getStrength() == BindingStrength.REQUIRED) - txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); + txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage())); else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet")) checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), value, stack); else if (!noExtensibleWarnings && !isOkExtension(value, vs)) - txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); + txWarningForLaterRemoval(element, errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage())); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { - txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet()), vs.getUrl(), getErrorMessage(vr.getMessage())); + txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeValueSet(binding.getValueSet()), getErrorMessage(vr.getMessage())); } } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java index 46067244e..6f53644d1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java @@ -402,7 +402,7 @@ public class BundleValidator extends BaseValidator{ if (r != null) { EntrySummary e = new EntrySummary(i, entry, r); entryList.add(e); - System.out.println("Found entry "+e.dbg()); +// System.out.println("Found entry "+e.dbg()); } i++; } @@ -415,10 +415,10 @@ public class BundleValidator extends BaseValidator{ EntrySummary t = entryForTarget(entryList, tgt); if (t != null ) { if (t != e) { - System.out.println("Entry "+e.getIndex()+" refers to "+t.getIndex()+" by ref '"+ref+"'"); +// System.out.println("Entry "+e.getIndex()+" refers to "+t.getIndex()+" by ref '"+ref+"'"); e.getTargets().add(t); } else { - System.out.println("Entry "+e.getIndex()+" refers to itself by '"+ref+"'"); +// System.out.println("Entry "+e.getIndex()+" refers to itself by '"+ref+"'"); } } } @@ -432,7 +432,7 @@ public class BundleValidator extends BaseValidator{ foundRevLinks = false; for (EntrySummary e : entryList) { if (!visited.contains(e)) { - System.out.println("Not visited "+e.getIndex()+" - check for reverse links"); +// System.out.println("Not visited "+e.getIndex()+" - check for reverse links"); boolean add = false; for (EntrySummary t : e.getTargets()) { if (visited.contains(t)) { @@ -443,7 +443,7 @@ public class BundleValidator extends BaseValidator{ warning(errors, IssueType.INFORMATIONAL, e.getEntry().line(), e.getEntry().col(), stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), isExpectedToBeReverse(e.getResource().fhirType()), I18nConstants.BUNDLE_BUNDLE_ENTRY_REVERSE, (e.getEntry().getChildValue(FULL_URL) != null ? "'" + e.getEntry().getChildValue(FULL_URL) + "'" : "")); - System.out.println("Found reverse links for "+e.getIndex()); +// System.out.println("Found reverse links for "+e.getIndex()); foundRevLinks = true; visitLinked(visited, e); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java index 04896f54a..648d1b08f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/CodeSystemValidator.java @@ -27,11 +27,16 @@ public class CodeSystemValidator extends BaseValidator { source = Source.InstanceValidator; this.timeTracker = timeTracker; } - + public void validateCodeSystem(List errors, Element cs, NodeStack stack, ValidationOptions options) { String url = cs.getNamedChildValue("url"); String content = cs.getNamedChildValue("content"); - + String caseSensitive = cs.getNamedChildValue("caseSensitive"); + String hierarchyMeaning = cs.getNamedChildValue("hierarchyMeaning"); + String supp = cs.getNamedChildValue("supplements"); + + metaChecks(errors, cs, stack, url, content, caseSensitive, hierarchyMeaning, !Utilities.noString(supp)); + String vsu = cs.getNamedChildValue("valueSet"); if (!Utilities.noString(vsu)) { hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE); @@ -46,7 +51,7 @@ public class CodeSystemValidator extends BaseValidator { if (rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs.getCompose().getInclude().size() == 1, I18nConstants.CODESYSTEM_CS_VS_INVALID, url, vsu)) { if (rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs.getCompose().getInclude().get(0).getSystem().equals(url), I18nConstants.CODESYSTEM_CS_VS_WRONGSYSTEM, url, vsu, vs.getCompose().getInclude().get(0).getSystem())) { rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !vs.getCompose().getInclude().get(0).hasValueSet() - && !vs.getCompose().getInclude().get(0).hasConcept() && !vs.getCompose().getInclude().get(0).hasFilter(), I18nConstants.CODESYSTEM_CS_VS_INCLUDEDETAILS, url, vsu); + && !vs.getCompose().getInclude().get(0).hasConcept() && !vs.getCompose().getInclude().get(0).hasFilter(), I18nConstants.CODESYSTEM_CS_VS_INCLUDEDETAILS, url, vsu); if (vs.hasExpansion()) { int count = countConcepts(cs); rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs.getExpansion().getContains().size() == count, I18nConstants.CODESYSTEM_CS_VS_EXP_MISMATCH, url, vsu, count, vs.getExpansion().getContains().size()); @@ -56,8 +61,7 @@ public class CodeSystemValidator extends BaseValidator { } } } // todo... try getting the value set the other way... - - String supp = cs.getNamedChildValue("supplements"); + if (supp != null) { if (context.supportsSystem(supp)) { List concepts = cs.getChildrenByName("concept"); @@ -74,13 +78,82 @@ public class CodeSystemValidator extends BaseValidator { } } + private void metaChecks(List errors, Element cs, NodeStack stack, String url, String content, String caseSensitive, String hierarchyMeaning, boolean isSupplement) { + if (isSupplement) { + if (!"supplement".equals(content)) { + NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); + rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG); + } + if (!Utilities.noString(caseSensitive)) { + NodeStack s = stack.push(cs.getNamedChild("caseSensitive"), -1, null, null); + rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive"); + } + if (!Utilities.noString(hierarchyMeaning)) { + NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning"), -1, null, null); + rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive"); + } + + } else { + boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org")); + if (Utilities.noString(content)) { + NodeStack s = stack; + Element c = cs.getNamedChild("content"); + if (c != null) { + s = stack.push(c, -1, null, null); + } + if (isHL7) { + rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHALL, "content"); + } else { + warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "content"); + } + } else if ("supplement".equals(content)) { + NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); + rule(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING); + } + if (Utilities.noString(caseSensitive)) { + NodeStack s = stack; + Element c = cs.getNamedChild("caseSensitive"); + if (c != null) { + s = stack.push(c, -1, null, null); + } + if (isHL7) { + warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD, "caseSensitive"); + } else { + hint(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "caseSensitive"); + } + } + if (Utilities.noString(hierarchyMeaning) && hasHeirarchy(cs)) { + NodeStack s = stack; + Element c = cs.getNamedChild("hierarchyMeaning"); + if (c != null) { + s = stack.push(c, -1, null, null); + } + if (isHL7) { + warning(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_MISSING_ELEMENT_SHOULD, "hierarchyMeaning"); + } else { + hint(errors, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "hierarchyMeaning"); + } + } + } + } + + + private boolean hasHeirarchy(Element cs) { + for (Element c : cs.getChildren("concept")) { + if (c.hasChildren("concept")) { + return true; + } + } + return false; + } + private void validateSupplementConcept(List errors, Element concept, NodeStack stack, String supp, ValidationOptions options) { String code = concept.getChildValue("code"); if (!Utilities.noString(code)) { org.hl7.fhir.r5.context.IWorkerContext.ValidationResult res = context.validateCode(options, systemFromCanonical(supp), versionFromCanonical(supp), code, null); rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), res.isOk(), I18nConstants.CODESYSTEM_CS_SUPP_INVALID_CODE, supp, code); } - + } private int countConcepts(Element cs) {