Fix where validator was ignoring minimum cardinality for XML attributes (especially in CDA)

This commit is contained in:
Grahame Grieve 2024-02-25 19:25:17 +11:00
parent 1d4898eee6
commit 1eb8067d6b

View File

@ -156,6 +156,7 @@ import org.hl7.fhir.r5.model.TimeType;
import org.hl7.fhir.r5.model.Timing; import org.hl7.fhir.r5.model.Timing;
import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.UrlType; import org.hl7.fhir.r5.model.UrlType;
import org.hl7.fhir.r5.model.UsageContext;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.renderers.DataRenderer; import org.hl7.fhir.r5.renderers.DataRenderer;
@ -494,18 +495,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
Element e = new ObjectConverter(context).convert((Resource) item); Element e = new ObjectConverter(context).convert((Resource) item);
setParents(e); setParents(e);
self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null,
mode, false); mode, false, false);
} catch (IOException e1) { } catch (IOException e1) {
throw new FHIRException(e1); throw new FHIRException(e1);
} }
} else if (item instanceof Element) { } else if (item instanceof Element) {
Element e = (Element) item; Element e = (Element) item;
if (e.getSpecial() == SpecialElement.CONTAINED) { if (e.getSpecial() == SpecialElement.CONTAINED) {
self.validateResource(new ValidationContext(ctxt.getAppContext(), e, ctxt.getRootResource(), ctxt.getGroupingResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false); self.validateResource(new ValidationContext(ctxt.getAppContext(), e, ctxt.getRootResource(), ctxt.getGroupingResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false, false);
} else if (e.getSpecial() != null) { } else if (e.getSpecial() != null) {
self.validateResource(new ValidationContext(ctxt.getAppContext(), e, e, ctxt.getRootResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false); self.validateResource(new ValidationContext(ctxt.getAppContext(), e, e, ctxt.getRootResource()), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false, false);
} else { } else {
self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false); self.validateResource(new ValidationContext(ctxt.getAppContext(), e), valerrors, e, e, sd, IdStatus.OPTIONAL, new NodeStack(context, null, e, validationLanguage), null, mode, false, false);
} }
} else } else
throw new NotImplementedException(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCONFORMSTOPROFILE_WHEN_ITEM_IS_NOT_AN_ELEMENT)); throw new NotImplementedException(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESCONFORMSTOPROFILE_WHEN_ITEM_IS_NOT_AN_ELEMENT));
@ -603,7 +604,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private List<BundleValidationRule> bundleValidationRules = new ArrayList<>(); private List<BundleValidationRule> bundleValidationRules = new ArrayList<>();
private boolean validateValueSetCodesOnTxServer = true; private boolean validateValueSetCodesOnTxServer = true;
private QuestionnaireMode questionnaireMode; private QuestionnaireMode questionnaireMode;
private ValidationOptions baseOptions = new ValidationOptions(FhirPublication.R5);
private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>(); private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>();
private boolean logProgress; private boolean logProgress;
private CodingsObserver codingObserver; private CodingsObserver codingObserver;
@ -1002,7 +1002,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
long t = System.nanoTime(); long t = System.nanoTime();
NodeStack stack = new NodeStack(context, path, element, validationLanguage); NodeStack stack = new NodeStack(context, path, element, validationLanguage);
if (profiles == null || profiles.isEmpty()) { if (profiles == null || profiles.isEmpty()) {
validateResource(new ValidationContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition), false); validateResource(new ValidationContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition), false, false);
} else { } else {
int i = 0; int i = 0;
while (i < profiles.size()) { while (i < profiles.size()) {
@ -1020,7 +1020,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
i++; i++;
} }
for (StructureDefinition defn : profiles) { for (StructureDefinition defn : profiles) {
validateResource(new ValidationContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile), false); validateResource(new ValidationContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile), false, false);
} }
} }
if (hintAboutNonMustSupport) { if (hintAboutNonMustSupport) {
@ -2399,7 +2399,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else if (sd.getType().equals(resource.fhirType())) { } else if (sd.getType().equals(resource.fhirType())) {
List<ValidationMessage> valerrors = new ArrayList<ValidationMessage>(); List<ValidationMessage> valerrors = new ArrayList<ValidationMessage>();
ValidationMode mode = new ValidationMode(ValidationReason.Expression, ProfileSource.FromExpression); ValidationMode mode = new ValidationMode(ValidationReason.Expression, ProfileSource.FromExpression);
validateResource(new ValidationContext(appContext, resource), valerrors, resource, resource, sd, IdStatus.OPTIONAL, new NodeStack(context, null, resource, validationLanguage), null, mode, false); validateResource(new ValidationContext(appContext, resource), valerrors, resource, resource, sd, IdStatus.OPTIONAL, new NodeStack(context, null, resource, validationLanguage), null, mode, false, false);
boolean ok = true; boolean ok = true;
List<ValidationMessage> record = new ArrayList<>(); List<ValidationMessage> record = new ArrayList<>();
for (ValidationMessage v : valerrors) { for (ValidationMessage v : valerrors) {
@ -3070,11 +3070,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public boolean validateReference(ValidationContext valContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, String url) { public boolean validateReference(ValidationContext valContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, String url) {
boolean ok = true; boolean ok = true;
if (url.startsWith("#")) {
valContext.getInternalRefs().add(url.substring(1));
}
// now, do we check the URI target? // now, do we check the URI target?
if (fetcher != null && !type.equals("uuid")) { if (fetcher != null && !type.equals("uuid")) {
if (url.startsWith("#")) {
valContext.getInternalRefs().add(url.substring(1));
}
boolean found; boolean found;
try { try {
found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) /* || (url.startsWith("http://hl7.org/fhir/tools")) */ || found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) /* || (url.startsWith("http://hl7.org/fhir/tools")) */ ||
@ -3993,7 +3993,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
for (StructureDefinition pr : profiles) { for (StructureDefinition pr : profiles) {
List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>(); List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
validateResource(we.valContext(valContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, validateResource(we.valContext(valContext, pr), profileErrors, we.getResource(), we.getFocus(), pr,
IdStatus.OPTIONAL, we.getStack().resetIds(), pct, vmode.withReason(ValidationReason.MatchingSlice), true); IdStatus.OPTIONAL, we.getStack().resetIds(), pct, vmode.withReason(ValidationReason.MatchingSlice), true, false);
if (!hasErrors(profileErrors)) { if (!hasErrors(profileErrors)) {
goodCount++; goodCount++;
goodProfiles.put(pr, profileErrors); goodProfiles.put(pr, profileErrors);
@ -5379,7 +5379,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
// checkSpecials = we're only going to run these tests if we are actually validating this content (as opposed to we looked it up) // checkSpecials = we're only going to run these tests if we are actually validating this content (as opposed to we looked it up)
private boolean start(ValidationContext valContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, PercentageTracker pct, ValidationMode mode) throws FHIRException { private boolean start(ValidationContext valContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, PercentageTracker pct, ValidationMode mode, boolean fromContained) throws FHIRException {
boolean ok = !hasErrors(errors); boolean ok = !hasErrors(errors);
checkLang(resource, stack); checkLang(resource, stack);
@ -5399,7 +5399,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
resolveBundleReferences(element, new ArrayList<Element>()); resolveBundleReferences(element, new ArrayList<Element>());
} }
ok = startInner(valContext, errors, resource, element, defn, stack, valContext.isCheckSpecials(), pct, mode) && ok; ok = startInner(valContext, errors, resource, element, defn, stack, valContext.isCheckSpecials(), pct, mode, fromContained) && ok;
if (pctOwned) { if (pctOwned) {
pct.done(); pct.done();
} }
@ -5418,7 +5418,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (pctOwned) { if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress); pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress);
} }
ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency), fromContained) && ok;
if (pctOwned) { if (pctOwned) {
pct.done(); pct.done();
} }
@ -5466,7 +5466,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (pctOwned) { if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl(), logProgress); pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl(), logProgress);
} }
ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.MetaProfile)) && ok; ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.MetaProfile), fromContained) && ok;
if (pctOwned) { if (pctOwned) {
pct.done(); pct.done();
} }
@ -5483,7 +5483,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (pctOwned) { if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress); pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress);
} }
ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; ok = startInner(valContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency), fromContained) && ok;
if (pctOwned) { if (pctOwned) {
pct.done(); pct.done();
} }
@ -5510,7 +5510,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (pctOwned) { if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getVersionedUrl(), logProgress); pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getVersionedUrl(), logProgress);
} }
ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.GlobalProfile)) && ok; ok = startInner(valContext, errors, resource, element, sd, stack, false, pct, mode.withSource(ProfileSource.GlobalProfile), fromContained) && ok;
if (pctOwned) { if (pctOwned) {
pct.done(); pct.done();
} }
@ -5611,7 +5611,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
public boolean startInner(ValidationContext valContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { public boolean startInner(ValidationContext valContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean fromContained) {
// the first piece of business is to see if we've validated this resource against this profile before. // the first piece of business is to see if we've validated this resource against this profile before.
// if we have (*or if we still are*), then we'll just return our existing errors // if we have (*or if we still are*), then we'll just return our existing errors
boolean ok = true; boolean ok = true;
@ -5641,13 +5641,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
ok = false; ok = false;
} }
if (checkSpecials) { if (checkSpecials) {
ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode) && ok; ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode, fromContained) && ok;
ok = validateResourceRules(errors, element, stack) && ok; ok = validateResourceRules(errors, element, stack) && ok;
} }
return ok; return ok;
} }
public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean contained) {
boolean ok = true; boolean ok = true;
long t = System.nanoTime(); long t = System.nanoTime();
@ -5663,7 +5663,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
if (isHL7Core(element) && !isExample()) { if (isHL7Core(element) && !isExample()) {
ok = checkPublisherConsistency(errors, element, stack) && ok; ok = checkPublisherConsistency(valContext, errors, element, stack, contained) && ok;
} }
} }
if (element.getType().equals(BUNDLE)) { if (element.getType().equals(BUNDLE)) {
@ -5709,11 +5709,38 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
private boolean checkPublisherConsistency(List<ValidationMessage> errors, Element element, NodeStack stack) { private boolean checkPublisherConsistency(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean contained) {
String pub = element.getNamedChildValue("publisher", false); String pub = element.getNamedChildValue("publisher", false);
Base wgT = element.getExtensionValue(ToolingExtensions.EXT_WORKGROUP); Base wgT = element.getExtensionValue(ToolingExtensions.EXT_WORKGROUP);
String wg = wgT == null ? null : wgT.primitiveValue(); String wg = wgT == null ? null : wgT.primitiveValue();
if (contained && wg == null) {
boolean ok = true;
Element container = valContext.getRootResource();
if (element.hasExtension(ToolingExtensions.EXT_WORKGROUP)) {
// container already specified the HL7 WG, so we don't need to test
// but we're still going to test pub if it exists
if (pub != null) {
wgT = container.getExtensionValue(ToolingExtensions.EXT_WORKGROUP);
wg = wgT == null ? null : wgT.primitiveValue();
HL7WorkGroup wgd = HL7WorkGroups.find(wg);
if (wgd != null) {
String rpub = "HL7 International / "+wgd.getName();
ok = rpub.equals(pub);
if (!ok && wgd.getName2() != null) {
ok = ("HL7 International / "+wgd.getName2()).equals(pub);
warningOrError(pub.contains("/"), errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), ok, I18nConstants.VALIDATION_HL7_PUBLISHER_MISMATCH2, wg, rpub, "HL7 International / "+wgd.getName2(), pub);
} else {
warningOrError(pub.contains("/"), errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), ok, I18nConstants.VALIDATION_HL7_PUBLISHER_MISMATCH, wg, rpub, pub);
}
}
}
return ok;
}
}
List<String> urls = new ArrayList<>(); List<String> urls = new ArrayList<>();
for (Element c : element.getChildren("contact")) { for (Element c : element.getChildren("contact")) {
for (Element t : c.getChildren("telecom")) { for (Element t : c.getChildren("telecom")) {
@ -5722,6 +5749,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
} }
if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wg != null, I18nConstants.VALIDATION_HL7_WG_NEEDED, ToolingExtensions.EXT_WORKGROUP)) { if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wg != null, I18nConstants.VALIDATION_HL7_WG_NEEDED, ToolingExtensions.EXT_WORKGROUP)) {
HL7WorkGroup wgd = HL7WorkGroups.find(wg); HL7WorkGroup wgd = HL7WorkGroups.find(wg);
if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wgd != null, I18nConstants.VALIDATION_HL7_WG_UNKNOWN, wg)) { if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wgd != null, I18nConstants.VALIDATION_HL7_WG_UNKNOWN, wg)) {
@ -5739,7 +5767,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
Utilities.startsWithInList( wgd.getLink(), urls), I18nConstants.VALIDATION_HL7_WG_URL, wg, wgd.getLink()); Utilities.startsWithInList( wgd.getLink(), urls), I18nConstants.VALIDATION_HL7_WG_URL, wg, wgd.getLink());
return true; return true;
} }
} }
return false; return false;
} }
@ -5924,7 +5953,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
checkSpecials(valContext, errors, element, stack, ok, pct, mode); checkSpecials(valContext, errors, element, stack, ok, pct, mode, true);
if (typeForResource.getProfile().size() == 1) { if (typeForResource.getProfile().size() == 1) {
long t = System.nanoTime(); long t = System.nanoTime();
@ -5933,7 +5962,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special == null ? "??" : special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) { profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_EXPL, special == null ? "??" : special.toHuman(), resourceName, typeForResource.getProfile().get(0).asStringValue())) {
trackUsage(profile, valContext, element); trackUsage(profile, valContext, element);
ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode, false) && ok; ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode, false, special == SpecialElement.CONTAINED) && ok;
} else { } else {
ok = false; ok = false;
} }
@ -5945,7 +5974,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
trackUsage(profile, valContext, element); trackUsage(profile, valContext, element);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) { profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), resourceName)) {
ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode, false) && ok; ok = validateResource(hc, errors, resource, element, profile, idstatus, stack, pct, mode, false, special == SpecialElement.CONTAINED) && ok;
} else { } else {
ok = false; ok = false;
} }
@ -5966,7 +5995,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
trackUsage(profile, valContext, element); trackUsage(profile, valContext, element);
List<ValidationMessage> perrors = new ArrayList<>(); List<ValidationMessage> perrors = new ArrayList<>();
errorsList.add(perrors); errorsList.add(perrors);
if (validateResource(hc, perrors, resource, element, profile, idstatus, stack, pct, mode, false)) { if (validateResource(hc, perrors, resource, element, profile, idstatus, stack, pct, mode, false, special == SpecialElement.CONTAINED)) {
bm.append(u.asStringValue()); bm.append(u.asStringValue());
matched++; matched++;
} }
@ -6228,7 +6257,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
String stype = ei.getElement().fhirType(); String stype = ei.getElement().fhirType();
if (!stype.equals(type)) { if (stype == null || !stype.equals(type)) {
if (checkDefn.isChoice()) { if (checkDefn.isChoice()) {
if (extensionUrl != null && !isAbsolute(extensionUrl)) { if (extensionUrl != null && !isAbsolute(extensionUrl)) {
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getVersionedUrl(), type, stype) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getVersionedUrl(), type, stype) && ok;
@ -6655,7 +6684,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean ok = true; boolean ok = true;
// 3. report any definitions that have a cardinality problem // 3. report any definitions that have a cardinality problem
for (ElementDefinition ed : childDefinitions.getList()) { for (ElementDefinition ed : childDefinitions.getList()) {
if (ed.getRepresentation().isEmpty()) { // ignore xml attributes if (!ed.hasRepresentation(PropertyRepresentation.XHTML) && !ed.hasRepresentation(PropertyRepresentation.XMLTEXT)) { // xhtml.value is XMLText in <R3
int count = 0; int count = 0;
List<ElementDefinition> slices = null; List<ElementDefinition> slices = null;
if (ed.hasSlicing()) { if (ed.hasSlicing()) {
@ -7043,9 +7072,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return true; return true;
} }
boolean ok = true; boolean ok = true;
if (debug) {
System.out.println("inv "+inv.getKey()+" on "+path+" in "+resource.fhirType()+" {{ "+inv.getExpression()+" }}"+time());
}
// we don't allow dom-3 to execute - it takes too long (and is wrong). // we don't allow dom-3 to execute - it takes too long (and is wrong).
// instead, we enforce it in code // instead, we enforce it in code
if ("dom-3".equals(inv.getKey())) { if ("dom-3".equals(inv.getKey())) {
@ -7123,7 +7149,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
* The actual base entry point for internal use (re-entrant) * The actual base entry point for internal use (re-entrant)
*/ */
private boolean validateResource(ValidationContext valContext, List<ValidationMessage> errors, Element resource, private boolean validateResource(ValidationContext valContext, List<ValidationMessage> errors, Element resource,
Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack, PercentageTracker pct, ValidationMode mode, boolean forReference) throws FHIRException { Element element, StructureDefinition defn, IdStatus idstatus, NodeStack stack, PercentageTracker pct, ValidationMode mode, boolean forReference, boolean fromContained) throws FHIRException {
boolean ok = true; boolean ok = true;
// check here if we call validation policy here, and then change it to the new interface // check here if we call validation policy here, and then change it to the new interface
@ -7175,7 +7201,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// validate // validate
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), checkResourceName(defn, resourceName, element.getFormat()), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE, if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), checkResourceName(defn, resourceName, element.getFormat()), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE,
defn.getType(), resourceName, defn.getVersionedUrl())) { defn.getType(), resourceName, defn.getVersionedUrl())) {
ok = start(valContext, errors, element, element, defn, stack, pct, mode) && ok; // root is both definition and type ok = start(valContext, errors, element, element, defn, stack, pct, mode, fromContained) && ok; // root is both definition and type
} else { } else {
ok = false; ok = false;
} }
@ -7215,6 +7241,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
Set<String> baseRefs, List<Element> containedList, int i, Element contained) { Set<String> baseRefs, List<Element> containedList, int i, Element contained) {
NodeStack n = stack.push(contained, i, null, null); NodeStack n = stack.push(contained, i, null, null);
boolean found = isReferencedFromBase(contained, baseRefs, containedList, new ArrayList<>()); boolean found = isReferencedFromBase(contained, baseRefs, containedList, new ArrayList<>());
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, n, found, I18nConstants.CONTAINED_ORPHAN_DOM3, contained.getIdBase()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, n, found, I18nConstants.CONTAINED_ORPHAN_DOM3, contained.getIdBase()) && ok;
return ok; return ok;
} }
@ -7232,8 +7259,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (c != contained && !ignoreList.contains(c)) { // ignore list is to prevent getting into an unterminated loop if (c != contained && !ignoreList.contains(c)) { // ignore list is to prevent getting into an unterminated loop
Set<String> refs = (Set<String>) c.getUserData(ValidationContext.INTERNAL_REFERENCES_NAME); Set<String> refs = (Set<String>) c.getUserData(ValidationContext.INTERNAL_REFERENCES_NAME);
List<Element> ignoreList2 = new ArrayList<Element>(); List<Element> ignoreList2 = new ArrayList<Element>();
ignoreList.addAll(ignoreList); ignoreList2.addAll(ignoreList);
ignoreList.add(c); ignoreList2.add(c);
if (refs != null && refs.contains(id) && isReferencedFromBase(c, baseRefs, containedList, ignoreList2)) { if (refs != null && refs.contains(id) && isReferencedFromBase(c, baseRefs, containedList, ignoreList2)) {
return true; return true;
} }
@ -7266,11 +7293,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
String s = b.toString(); String s = b.toString();
if (debug) { // if (debug) {
System.out.println("OK = "+ok+" for "+path); // System.out.println("OK = "+ok+" for "+path);
System.out.println("Errs = "+errors.toString()); // System.out.println("Errs = "+errors.toString());
System.out.println("Ids = "+s); // System.out.println("Ids = "+s);
} // }
return s; return s;
} }
@ -7692,4 +7719,5 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
return this; return this;
} }
} }