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 a16f87af6..92da0ba48 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 @@ -112,10 +112,17 @@ public class ValueSetCheckerSimple implements ValueSetChecker { if (system == null && !code.hasDisplay()) { // dealing with just a plain code (enum) system = systemForCodeInValueSet(code.getCode()); } - if (!code.hasSystem()) + if (!code.hasSystem()) { + if (options.isGuessSystem() && system == null && Utilities.isAbsoluteUrl(code.getCode())) { + system = "urn:ietf:rfc:3986"; // this arises when using URIs bound to value sets + } code.setSystem(system); + } inExpansion = checkExpansion(code); CodeSystem cs = context.fetchCodeSystem(system); + if (cs == null) { + cs = findSpecialCodeSystem(system); + } if (cs == null) { warningMessage = "Unable to resolve system "+system+" - system is not specified or implicit"; if (!inExpansion) @@ -123,7 +130,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker { } if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) { warningMessage = "Unable to resolve system "+system+" - system is not complete"; - if (!inExpansion) + if (!inExpansion && cs.getContent() != CodeSystemContentMode.FRAGMENT) // we're going to give it a go if it's a fragment throw new FHIRException(warningMessage); } @@ -147,6 +154,17 @@ public class ValueSetCheckerSimple implements ValueSetChecker { return res; } + private CodeSystem findSpecialCodeSystem(String system) { + if ("urn:ietf:rfc:3986".equals(system)) { + CodeSystem cs = new CodeSystem(); + cs.setUrl(system); + cs.setUserData("tx.cs.special", new URICodeSystem()); + cs.setContent(CodeSystemContentMode.COMPLETE); + return cs; + } + return null; + } + boolean checkExpansion(Coding code) { if (valueset==null || !valueset.hasExpansion()) return false; @@ -164,9 +182,14 @@ public class ValueSetCheckerSimple implements ValueSetChecker { } private ValidationResult validateCode(Coding code, CodeSystem cs) { - ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), code.getCode()); - if (cc == null) - return new ValidationResult(IssueSeverity.ERROR, context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, gen(code), cs.getUrl())); + ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode()); + if (cc == null) { + if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { + return new ValidationResult(IssueSeverity.ERROR, context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_FRAGMENT, gen(code), cs.getUrl())); + } else { + return new ValidationResult(IssueSeverity.ERROR, context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, gen(code), cs.getUrl())); + } + } if (code.getDisplay() == null) return new ValidationResult(cc); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); 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 de582ba07..99cef465a 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 @@ -419,6 +419,7 @@ public class I18nConstants { public final static String UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__ = "Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__"; public final static String DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF_ = "Display_Name_for__should_be_one_of__instead_of_"; public final static String UNKNOWN_CODE__IN_ = "Unknown_Code__in_"; + public final static String UNKNOWN_CODE__IN_FRAGMENT = "UNKNOWN_CODE__IN_FRAGMENT"; public final static String CODE_FOUND_IN_EXPANSION_HOWEVER_ = "Code_found_in_expansion_however_"; public final static String NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "None_of_the_provided_codes_are_in_the_value_set_"; public final static String CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE = "Coding_has_no_system__cannot_validate"; diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 8c6c8df96..0e8e00c87 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -419,6 +419,7 @@ Error_parsing_ = Error parsing {0}:{1} Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__ = Unable to connect to terminology server. Use parameter ''-tx n/a'' tun run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = {0} Display_Name_for__should_be_one_of__instead_of_ = Display Name for {0}#{1} should be one of ''{2}'' instead of ''{3}'' Unknown_Code__in_ = Unknown Code {0} in {1} +UNKNOWN_CODE__IN_FRAGMENT = Unknown Code {0} in {1} - note that the code system is labelled as a fragment, so the code may be valid in some other fragment Code_found_in_expansion_however_ = Code found in expansion, however: {0} None_of_the_provided_codes_are_in_the_value_set_ = None of the provided codes are in the value set {0} Coding_has_no_system__cannot_validate = Coding has no system - cannot validate