Fix up support for inactive codes and fix error message syntax

This commit is contained in:
Grahame Grieve 2023-08-04 18:44:40 +10:00
parent f1571ea2b4
commit 4727bc57ff
8 changed files with 31 additions and 40 deletions

View File

@ -544,9 +544,10 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
if (s.startsWith("version=")) { if (s.startsWith("version=")) {
if (version == null) if (version == null)
version = s.substring(8); version = s.substring(8);
else if (!version.equals(s.substring(8))) else if (!version.equals(s.substring(8))) {
throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8))); throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8)));
} }
}
if (s.startsWith("revision=")) if (s.startsWith("revision="))
revision = s.substring(9); revision = s.substring(9);
if (s.startsWith("date=")) if (s.startsWith("date="))

View File

@ -498,6 +498,14 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
} }
} }
public void copyNewExtensions(org.hl7.fhir.r5.model.Element src, String... urls) {
for (Extension e : src.getExtension()) {
if (Utilities.existsInList(e.getUrl(), urls) && !!hasExtension(e.getUrl())) {
addExtension(e.copy());
}
}
}
// end addition // end addition

View File

@ -369,6 +369,10 @@ public class CodeSystemUtilities {
if ("inactive".equals(p.getCode()) && p.hasValueBooleanType()) { if ("inactive".equals(p.getCode()) && p.hasValueBooleanType()) {
return p.getValueBooleanType().getValue(); return p.getValueBooleanType().getValue();
} }
if ("inactive".equals(p.getCode()) && p.hasValueCodeType()) {
String code = p.getValueCodeType().primitiveValue();
return "true".equals(code);
}
} }
return false; return false;
} }

View File

@ -29,7 +29,7 @@ public class ValidationProcessInfo {
return issues; return issues;
} }
public void addIssue(List<OperationOutcomeIssueComponent> issues) { public void addIssue(List<OperationOutcomeIssueComponent> issues) {
issues.addAll(issues); this.issues.addAll(issues);
} }
public boolean hasErrors() { public boolean hasErrors() {

View File

@ -214,7 +214,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
} }
} else { } else {
c.setUserData("cs", cs); c.setUserData("cs", cs);
res = validateCode(path+".coding["+i+"]", c, cs, vcc); res = validateCode(path+".coding["+i+"]", c, cs, vcc, info);
} }
info.getIssues().addAll(res.getIssues()); info.getIssues().addAll(res.getIssues());
i++; i++;
@ -349,6 +349,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
boolean inExpansion = false; boolean inExpansion = false;
boolean inInclude = false; boolean inInclude = false;
List<OperationOutcomeIssueComponent> issues = new ArrayList<>(); List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
ValidationProcessInfo info = new ValidationProcessInfo(issues);
VersionInfo vi = new VersionInfo(this); VersionInfo vi = new VersionInfo(this);
checkCanonical(issues, path, valueset); checkCanonical(issues, path, valueset);
@ -439,7 +440,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
// we can't validate that here. // we can't validate that here.
throw new FHIRException("Unable to evaluate based on empty code system"); throw new FHIRException("Unable to evaluate based on empty code system");
} }
res = validateCode(path, code, cs, null); res = validateCode(path, code, cs, null, info);
res.setIssues(issues); res.setIssues(issues);
} else if (cs == null && valueset.hasExpansion() && inExpansion) { } else if (cs == null && valueset.hasExpansion() && inExpansion) {
// we just take the value set as face value then // we just take the value set as face value then
@ -460,7 +461,6 @@ public class ValueSetValidator extends ValueSetProcessBase {
} }
String wv = vi.getVersion(system, code.getVersion()); String wv = vi.getVersion(system, code.getVersion());
ValidationProcessInfo info = new ValidationProcessInfo(issues);
// then, if we have a value set, we check it's in the value set // then, if we have a value set, we check it's in the value set
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) { if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
@ -633,7 +633,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
return false; return false;
} }
private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc) { private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc, ValidationProcessInfo info) {
ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), allAltCodes); ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), allAltCodes);
if (cc == null) { if (cc == null) {
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
@ -648,6 +648,9 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (vcc != null) { if (vcc != null) {
vcc.addCoding(vc); vcc.addCoding(vc);
} }
if (CodeSystemUtilities.isInactive(cs, cc)) {
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.EXPIRED, path, context.formatMessage(I18nConstants.INACTIVE_CODE_WARNING, cc.getCode())));
}
boolean ws = false; boolean ws = false;
if (code.getDisplay() == null) { if (code.getDisplay() == null) {
return new ValidationResult(code.getSystem(), cs.getVersion(), cc, vc.getDisplay()); return new ValidationResult(code.getSystem(), cs.getVersion(), cc, vc.getDisplay());
@ -1081,6 +1084,12 @@ public class ValueSetValidator extends ValueSetProcessBase {
} }
} else { } else {
checkCanonical(info.getIssues(), path, cs); checkCanonical(info.getIssues(), path, cs);
if (valueset.getCompose().hasInactive() && !valueset.getCompose().getInactive()) {
if (CodeSystemUtilities.isInactive(cs, code)) {
return false;
}
}
if (vsi.hasFilter()) { if (vsi.hasFilter()) {
ok = true; ok = true;
for (ConceptSetFilterComponent f : vsi.getFilter()) { for (ConceptSetFilterComponent f : vsi.getFilter()) {

View File

@ -286,34 +286,4 @@ public class XVerExtensionManager {
} }
} }
public String getReference(String url) {
String version = getVersion(url);
String base = VersionUtilities.getSpecUrl(version);
if (base == null) {
return null;
} else {
String path = url.substring(url.indexOf("-")+1);
if (!path.contains(".")) {
return null;
}
String type = path.substring(0, path.indexOf("."));
if (Utilities.existsInList(type, "Annotation", "Attachment", "Identifier", "CodeableConcept", "Coding", "Quantity", "Duration", "Range", "Period", "Ratio", "RatioRange", "SampledData", "Signature", "HumanName", "Address", "ContactPoint", "Timing")) {
return Utilities.pathURL(base, "datatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Element", "BackboneElement", "BackboneType", "PrimitiveType", "DataType", "Base")) {
return Utilities.pathURL(base, "types-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "UsageContext", "RelatedArtifact", "DataRequirement", "ParameterDefinition", "TriggerDefinition", "Expression", "ContactDetail", "ExtendedContactDetail", "VirtualServiceDetail", "Availability", "MonetaryComponent", "Contributor")) {
return Utilities.pathURL(base, "metadatatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Reference", "CodeableReference")) {
return Utilities.pathURL(base, "references-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Meta")) {
return Utilities.pathURL(base, "resource-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
return Utilities.pathURL(base, type.toLowerCase()+"-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
}
} }

View File

@ -954,9 +954,7 @@ public class I18nConstants {
public static final String MSG_DEPRECATED = "MSG_DEPRECATED"; public static final String MSG_DEPRECATED = "MSG_DEPRECATED";
public static final String MSG_WITHDRAWN = "MSG_WITHDRAWN"; public static final String MSG_WITHDRAWN = "MSG_WITHDRAWN";
public static final String MSG_RETIRED = "MSG_RETIRED"; public static final String MSG_RETIRED = "MSG_RETIRED";
public static final String INACTIVE_CODE_WARNING = "INACTIVE_CODE_WARNING";
} }

View File

@ -171,7 +171,7 @@ Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0
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_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_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server
Terminology_TX_NoValid_15A = The value provided (''{0}'') could not be validated because the code system {1} is not known Terminology_TX_NoValid_15A = The value provided (''{0}'') could not be validated because the code system {1} is not known
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_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_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_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_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})
@ -1011,3 +1011,4 @@ SD_EXTENSION_URL_MISMATCH = The fixed value for the extension URL is {1} which d
MSG_DEPRECATED = Reference to deprecated item {0} MSG_DEPRECATED = Reference to deprecated item {0}
MSG_WITHDRAWN = Reference to withdrawn item {0} MSG_WITHDRAWN = Reference to withdrawn item {0}
MSG_RETIRED = Reference to retired item {0} MSG_RETIRED = Reference to retired item {0}
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active