more work on code validation (#306)

* Handle unknown code systems better when checking codes from unknown systems

* more work on code validation

* more work on comparison

* hack workaround for UTG NUCC problem.

* adjust exception type

* more work on timeouts

* improve error message

* fix NPE?

* release notes

* Improve error message
This commit is contained in:
Grahame Grieve 2020-08-13 23:47:05 +10:00 committed by GitHub
parent 7faf5f97e4
commit 2c0fe519cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 152 additions and 37 deletions

View File

@ -0,0 +1,14 @@
Validator:
* add support for -bundle parameter to allow validating just one resource (/type) in a bundle
* improved reporting of errors and warnings for unknown code systems on required bindings
* pass dependencies to the server for imported value sets etc
* use server side caching for more efficient use of bandwidth
* Fix NPE loading packages from simplifier or old packages (and don't lazy load packages passed to command line)
Other code changes:
* further work on comparing CapabilityStatements (nearly, but not quite, finished)
* More work on timeouts in terminology client
* Fix for parsing error in R3/R4 sparse arrays for primitives types
* Improve terminology client logging
* don't reload a package if already loaded
* rendering: fix NPEs rendering patient summary, and render expressions for quantities

View File

@ -10,8 +10,11 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.BackboneElement;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent;
import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
@ -28,6 +31,8 @@ import org.hl7.fhir.r5.model.Element;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -406,7 +411,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
}
private void compareRestResource(StructuralMatch<Element> sm, CapabilityStatementRestResourceComponent l, CapabilityStatementRestResourceComponent r, String path, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) {
compareStrings(path, sm.getMessages(), l.getProfile(), r.getProfile(), "profile", IssueSeverity.WARNING, res);
compareProfiles(path, sm, l.getProfileElement(), r.getProfileElement(), res, union, intersection);
// todo: supported profiles
compareStrings(path, sm.getMessages(), l.getDocumentation(), r.getDocumentation(), "documentation", IssueSeverity.INFORMATION, res);
compareExpectations(sm, l, r, path, res, union, intersection);
@ -425,6 +430,57 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
compareOperations(sm, l.getOperation(), r.getOperation(), path, res, union.getOperation(), intersection.getOperation());
}
private void compareProfiles(String path, StructuralMatch<Element> combined, CanonicalType left, CanonicalType right, CapabilityStatementComparison res, CapabilityStatementRestResourceComponent union, CapabilityStatementRestResourceComponent intersection) {
if (!left.hasValue() && !right.hasValue()) {
// nothing in this case
} else if (!left.hasValue()) {
// the intersection is anything in right. The union is everything (or nothing, in this case)
intersection.setProfileElement(right.copy());
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.WARNING, "Added this profile", path), right).setName("profile"));
} else if (!right.hasValue()) {
// the intersection is anything in right. The union is everything (or nothing, in this case)
intersection.setProfileElement(left.copy());
combined.getChildren().add(new StructuralMatch<Element>(left, vmI(IssueSeverity.WARNING, "Removed this profile", path)).setName("profile"));
} else {
// profiles on both sides...
StructureDefinition sdLeft = session.getContextLeft().fetchResource(StructureDefinition.class, left.getValue());
StructureDefinition sdRight = session.getContextRight().fetchResource(StructureDefinition.class, right.getValue());
if (sdLeft == null && sdRight == null) {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.ERROR, "Cannot compare profiles because neither is known", path)).setName("profile"));
} else if (sdLeft == null) {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.ERROR, "Cannot compare profiles because '"+left.getValue()+"' is not known", path)).setName("profile"));
} else if (sdRight == null) {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.ERROR, "Cannot compare profiles because '"+right.getValue()+"' is not known", path)).setName("profile"));
} else if (sdLeft.getUrl().equals(sdRight.getUrl())) {
intersection.setProfileElement(left.copy());
union.setProfileElement(left.copy());
combined.getChildren().add(new StructuralMatch<Element>(left, right).setName("profile"));
} else if (profileInherits(sdLeft, sdRight, session.getContextLeft())) {
// if left inherits from right:
intersection.setProfileElement(left.copy());
union.setProfileElement(right.copy());
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.WARNING, "Changed this profile to a broader profile", path)).setName("profile"));
} else if (profileInherits(sdRight, sdLeft, session.getContextRight())) {
intersection.setProfileElement(right.copy());
union.setProfileElement(left.copy());
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.WARNING, "Changed this profile to a narrower one", path)).setName("profile"));
} else {
combined.getChildren().add(new StructuralMatch<Element>(left, right, vmI(IssueSeverity.WARNING, "Different", path)).setName("profile"));
throw new Error("Not done yet");
}
}
}
private boolean profileInherits(StructureDefinition sdFocus, StructureDefinition sdOther, IWorkerContext ctxt) {
while (sdFocus != null) {
if (sdFocus.getUrl().equals(sdOther.getUrl()) && sdFocus.getVersion().equals(sdOther.getVersion())) {
return true;
}
sdFocus = ctxt.fetchResource(StructureDefinition.class, sdFocus.getBaseDefinition());
}
return false;
}
private <T> void compareItemProperty(StructuralMatch<Element> combined, String name, PrimitiveType<T> left, PrimitiveType<T> right, String path, CapabilityStatementComparison res, PrimitiveType<T> union, PrimitiveType<T> intersection, IssueSeverity issueSeverity) {
if (!left.isEmpty() || !right.isEmpty()) {
if (left.isEmpty()) {
@ -846,9 +902,15 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
r.getCells().add(gen.new Cell(null, null, t.getName(), null, null));
PrimitiveType left = t.hasLeft() ? (PrimitiveType) t.getLeft() : null;
PrimitiveType right = t.hasRight() ? (PrimitiveType) t.getRight() : null;
r.getCells().add(style(gen.new Cell(null, null, left != null ? left.primitiveValue() : "", null, null), left != null ? left.primitiveValue() : null, right != null ? right.primitiveValue() : null, true));
CanonicalResource crL = left == null ? null : (CanonicalResource) session.getContextLeft().fetchResource(Resource.class, left.primitiveValue());
CanonicalResource crR = right == null ? null : (CanonicalResource) session.getContextRight().fetchResource(Resource.class, right.primitiveValue());
String refL = crL != null && crL.hasUserData("path") ? crL.getUserString("path") : null;
String dispL = crL != null && refL != null ? crL.present() : left == null ? "" : left.primitiveValue();
String refR = crR != null && crR.hasUserData("path") ? crR.getUserString("path") : null;
String dispR = crR != null && refR != null ? crR.present() : right == null ? "" : right.primitiveValue();
r.getCells().add(style(gen.new Cell(null, refL, dispL, null, null), left != null ? left.primitiveValue() : null, right != null ? right.primitiveValue() : null, true));
r.getCells().add(gen.new Cell(null, null, "", null, null));
r.getCells().add(style(gen.new Cell(null, null, right != null ? right.primitiveValue() : "", null, null), left != null ? left.primitiveValue() : null, right != null ? right.primitiveValue() : null, false));
r.getCells().add(style(gen.new Cell(null, refR, dispR, null, null), left != null ? left.primitiveValue() : null, right != null ? right.primitiveValue() : null, false));
r.getCells().add(gen.new Cell(null, null, "", null, null));
r.getCells().add(cellForMessages(gen, t.getMessages()));
return r;

View File

@ -242,7 +242,6 @@ public class CapabilityStatementUtilities {
tr.td().b().addText(r.getType());
tr.td().tx("Present");
if (o == null) {
union.addResource(r);
XhtmlNode p = tr.td().para("Absent");

View File

@ -970,7 +970,6 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
addDependentResources(pin, inc);
}
}
private void addDependentResources(Parameters pin, ConceptSetComponent inc) {

View File

@ -212,6 +212,11 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
}
public void see(CachedCanonicalResource<T> cr) {
// ignore UTG NUCC erroneous code system
if (cr.getPackageInfo() != null && cr.getPackageInfo().getId() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology") && "http://nucc.org/provider-taxonomy".equals(cr.getUrl())) {
return;
}
if (enforceUniqueId && map.containsKey(cr.getId())) {
drop(cr.getId());
}

View File

@ -36,6 +36,6 @@ import org.hl7.fhir.r5.utils.EOperationOutcome;
public interface ValueSetChecker {
boolean codeInValueSet(String system, String code) throws ETooCostly, EOperationOutcome, Exception;
Boolean codeInValueSet(String system, String code) throws ETooCostly, EOperationOutcome, Exception;
}

View File

@ -54,6 +54,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
@ -98,11 +99,18 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
}
}
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
boolean ok = false;
Boolean result = false;
for (Coding c : code.getCoding()) {
ok = ok || codeInValueSet(c.getSystem(), c.getCode());
Boolean ok = codeInValueSet(c.getSystem(), c.getCode());
if (ok == null && result == false) {
result = null;
} else if (ok) {
result = true;
}
if (!ok) {
}
if (result == null) {
warnings.add(0, context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl()));
} else if (!result) {
errors.add(0, context.formatMessage(I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getUrl()));
}
}
@ -119,7 +127,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
String warningMessage = null;
// first, we validate the concept itself
ValidationResult res =null;
ValidationResult res = null;
boolean inExpansion = false;
String system = code.hasSystem() ? code.getSystem() : getValueSetSystem();
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
@ -151,13 +159,20 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
}
if (cs != null /*&& (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)*/) {
if (!(cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)) {
// we can't validate that here.
throw new FHIRException("Unable to evaluate based on empty code system");
}
res = validateCode(code, cs);
} else {
// it's in the expansion, but we could find it in a code system
res = findCodeInExpansion(code);
// well, we didn't find a code system - try the expansion?
// disabled waiting for discussion
throw new FHIRException("No try the server");
}
} else {
inExpansion = checkExpansion(code);
// disabled waiting for discussion
throw new FHIRException("No try the server");
// inExpansion = checkExpansion(code);
}
// then, if we have a value set, we check it's in the value set
@ -416,24 +431,34 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
}
@Override
public boolean codeInValueSet(String system, String code) throws FHIRException {
public Boolean codeInValueSet(String system, String code) throws FHIRException {
Boolean result = false;
if (valueset.hasExpansion()) {
return checkExpansion(new Coding(system, code, null));
} else if (valueset.hasCompose()) {
boolean ok = false;
for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) {
ok = ok || inComponent(vsi, system, code, valueset.getCompose().getInclude().size() == 1);
Boolean ok = inComponent(vsi, system, code, valueset.getCompose().getInclude().size() == 1);
if (ok == null && result == false) {
result = null;
} else if (ok) {
result = true;
break;
}
}
for (ConceptSetComponent vsi : valueset.getCompose().getExclude()) {
ok = ok && !inComponent(vsi, system, code, valueset.getCompose().getInclude().size() == 1);
Boolean nok = inComponent(vsi, system, code, valueset.getCompose().getInclude().size() == 1);
if (nok == null && result == false) {
result = null;
} else if (!nok) {
result = false;
}
}
return ok;
}
return false;
return result;
}
private boolean inComponent(ConceptSetComponent vsi, String system, String code, boolean only) throws FHIRException {
private Boolean inComponent(ConceptSetComponent vsi, String system, String code, boolean only) throws FHIRException {
for (UriType uri : vsi.getValueSet()) {
if (inImport(uri.getValue(), system, code)) {
return true;
@ -463,6 +488,9 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
vs.setUrl(Utilities.makeUuidUrn());
vs.getCompose().addInclude(vsi);
ValidationResult res = context.validateCode(options.noClient(), new Coding(system, code, null), vs);
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
return null;
}
return res.isOk();
} else {
if (vsi.hasFilter()) {

View File

@ -310,7 +310,7 @@ public class ClientUtils {
} catch (InterruptedException e) {
}
} else {
if (tryCount > 1) {
if (tryCount > 4) {
System.out.println("Giving up: "+ioe.getMessage()+" (R5 / "+(System.currentTimeMillis()-t)+"ms / "+Utilities.describeSize(payload.length)+" for "+message+")");
}
throw new EFhirClientException("Error sending HTTP Post/Put Payload: "+ioe.getMessage(), ioe);

View File

@ -230,6 +230,7 @@ public class I18nConstants {
public static final String NEEDS_A_SNAPSHOT = "needs_a_snapshot";
public static final String NODE_TYPE__IS_NOT_ALLOWED = "Node_type__is_not_allowed";
public static final String NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "None_of_the_provided_codes_are_in_the_value_set_";
public static final String UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_";
public static final String NOT_DONE_YET = "Not_done_yet";
public static final String NOT_DONE_YET_CANT_FETCH_ = "not_done_yet_cant_fetch_";
public static final String NOT_DONE_YET_VALIDATORHOSTSERVICESCHECKFUNCTION = "Not_done_yet_ValidatorHostServicescheckFunction";
@ -363,7 +364,8 @@ public class I18nConstants {
public static final String TERMINOLOGY_TX_CONFIRM_1 = "Terminology_TX_Confirm_1";
public static final String TERMINOLOGY_TX_CONFIRM_2 = "Terminology_TX_Confirm_2";
public static final String TERMINOLOGY_TX_CONFIRM_3 = "Terminology_TX_Confirm_3";
public static final String TERMINOLOGY_TX_CONFIRM_4 = "Terminology_TX_Confirm_4";
public static final String TERMINOLOGY_TX_CONFIRM_4a = "Terminology_TX_Confirm_4a";
public static final String TERMINOLOGY_TX_CONFIRM_4b = "Terminology_TX_Confirm_4b";
public static final String TERMINOLOGY_TX_CONFIRM_5 = "Terminology_TX_Confirm_5";
public static final String TERMINOLOGY_TX_CONFIRM_6 = "Terminology_TX_Confirm_6";
public static final String TERMINOLOGY_TX_DISPLAY_WRONG = "Terminology_TX_Display_Wrong";

View File

@ -135,7 +135,8 @@ Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements
Terminology_TX_Confirm_1 = Could not confirm that the codes provided are in the value set {0} and a code from this value set is required (class = {1})
Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (class = {1})
Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the value set {0} and a code is recommended to come from this value set (class = {1})
Terminology_TX_Confirm_4 = Could not confirm that the codes provided are in the value set {0}, and a code from this value set is required
Terminology_TX_Confirm_4a = The code provided ({2}) is not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_4b = The codes provided ({2}) are not in the value set {0}, and a code from this value set is required: {1}
Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code
Terminology_TX_Confirm_6 = Could not confirm that the codes provided are in the value set {0}, and a code is recommended to come from this value set
Terminology_TX_Display_Wrong = Display should be ''{0}''
@ -146,18 +147,18 @@ Terminology_TX_Error_Coding2 = Error {0} validating Coding: {1}
Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} ({1}), and a code 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_12 = The Coding provided is not in the value set {0}, and a code is required from this value set. {1}
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. {1}
Terminology_TX_NoValid_14 = The Coding provided 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_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){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 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2})
Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2})
Terminology_TX_NoValid_4 = The Coding provided is not in the value set {0}, and a code is required from this value set{1}
Terminology_TX_NoValid_5 = The Coding provided is not in the value set {0}, and a code should come from this value set unless it has no suitable code{1}
Terminology_TX_NoValid_6 = The Coding provided is not in the value set {0}, and a code is recommended to come from this value set{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{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})
@ -596,3 +597,4 @@ BUNDLE_RULE_NONE = No Rule
BUNDLE_RULE_UNKNOWN = Bundle Rule refers to invalid resource {0}
BUNDLE_RULE_INVALID_INDEX = Bundle Rules index is invalid ({0})
BUNDLE_RULE_PROFILE_UNKNOWN = Bundle Rules profile {1} is unknown for {0}
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = Unable to determine whether the provided codes are in the value set {0} because the value set or code system is not known to the validator

View File

@ -1138,7 +1138,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER);
else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4, describeReference(binding.getValueSet(), valueset));
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(binding.getValueSet(), valueset), vr.getMessage(), system+"#"+code);
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"), c, stack);
@ -1150,15 +1150,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_4, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""));
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_4, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
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"), c, stack);
else
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""));
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code);
}
}
}
@ -1357,7 +1357,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER);
else if (vr.getErrorClass() != null && !vr.getErrorClass().isInfrastructure()) {
if (binding.getStrength() == BindingStrength.REQUIRED)
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4, describeReference(binding.getValueSet(), valueset));
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(binding.getValueSet(), valueset), vr.getMessage(), theSystem+"#"+theCode);
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"), c, stack);
@ -1369,7 +1369,7 @@ 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_12, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()));
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_12, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode);
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"), c, stack);
@ -1377,7 +1377,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode());
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()));
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode);
}
}
}

View File

@ -180,7 +180,6 @@ public class QuestionnaireValidator extends BaseValidator {
}
}
if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE)) {
long t = System.nanoTime();
Questionnaire qsrc = questionnaire.startsWith("#") ? loadQuestionnaire(element, questionnaire.substring(1)) : context.fetchResource(Questionnaire.class, questionnaire);
if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire)) {
boolean inProgress = "in-progress".equals(element.getNamedChildValue("status"));

View File

@ -8,6 +8,8 @@ import org.hl7.fhir.convertors.VersionConvertor_10_50;
import org.hl7.fhir.convertors.VersionConvertor_14_50;
import org.hl7.fhir.convertors.VersionConvertor_30_50;
import org.hl7.fhir.convertors.VersionConvertor_40_50;
import org.hl7.fhir.convertors.loaders.R4ToR5Loader;
import org.hl7.fhir.convertors.loaders.BaseLoaderR5.NullLoaderKnowledgeProvider;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
@ -104,6 +106,9 @@ public class ComparisonTests {
if (context == null) {
System.out.println("---- Load R5 ----------------------------------------------------------------");
context = TestingUtilities.context();
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
NpmPackage npm = pcm.loadPackage("hl7.fhir.us.core#3.1.0");
context.loadFromPackage(npm, new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}, new NullLoaderKnowledgeProvider()));
}
if (!new File(Utilities.path("[tmp]", "comparison")).exists()) {