Updated to check for Bundle.meta.lastUpdated in document bundles.

Rules for this are listed here: http://hl7.org/fhir/stu3/documents.html#content
This is related to an issue with documentation clarity (FHIR-26544) https://jira.hl7.org/browse/FHIR-26544

Also, in this ticket, I have taken some of the string variables used multiple times throughout the methods I touched and put them into final fields.
This commit is contained in:
markiantorno 2020-03-11 16:09:23 -04:00
parent c0c5b7f7ac
commit a097ca0e67
3 changed files with 118 additions and 81 deletions

View File

@ -167,6 +167,18 @@ import ca.uhn.fhir.util.ObjectUtil;
public class InstanceValidator extends BaseValidator implements IResourceValidator {
private final String META = "meta";
private final String ENTRY = "entry";
private final String DOCUMENT = "document";
private final String RESOURCE = "resource";
private final String MESSAGE = "message";
private final String ID = "id";
private final String PATH_ARG = ":0";
private final String FULL_URL = "fullUrl";
private final String TYPE = "type";
private final String BUNDLE = "Bundle";
private final String LAST_UPDATED = "lastUpdated";
private class ValidatorHostServices implements IEvaluationContext {
@Override
@ -247,13 +259,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public Base resolveInBundle(String url, Element bnd) {
if (bnd == null)
return null;
if (bnd.fhirType().equals("Bundle")) {
for (Element be : bnd.getChildrenByName("entry")) {
Element res = be.getNamedChild("resource");
if (bnd.fhirType().equals(BUNDLE)) {
for (Element be : bnd.getChildrenByName(ENTRY)) {
Element res = be.getNamedChild(RESOURCE);
if (res != null) {
String fullUrl = be.getChildValue("fullUrl");
String fullUrl = be.getChildValue(FULL_URL);
String rt = res.fhirType();
String id = res.getChildValue("id");
String id = res.getChildValue(ID);
if (url.equals(fullUrl))
return res;
if (url.equals(rt + "/" + id))
@ -1739,7 +1751,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void checkIdentifier(List<ValidationMessage> errors, String path, Element focus, Identifier fixed, String fixedSource, boolean pattern) {
checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern);
checkFixedValue(errors, path + ".type", focus.getNamedChild("type"), fixed.getType(), fixedSource, "type", focus, pattern);
checkFixedValue(errors, path + ".type", focus.getNamedChild(TYPE), fixed.getType(), fixedSource, TYPE, focus, pattern);
checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern);
checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern);
checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern);
@ -1802,7 +1814,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
rule(errors, IssueType.INVALID, e.line(), e.col(), path, found, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_URL_RESOLVE, url);
}
}
if (type.equals("id")) {
if (type.equals(ID)) {
// work around an old issue with ElementDefinition.id
if (!context.getPath().equals("ElementDefinition.id") && !VersionUtilities.versionsCompatible("1.4", this.context.getVersion())) {
rule(errors, IssueType.INVALID, e.line(), e.col(), path, FormatUtilities.isValidId(e.primitiveValue()), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ID_VALID, e.primitiveValue());
@ -1971,7 +1983,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
), I18nConstants.XHTML_XHTML_ELEMENT_ILLEGAL, node.getName());
for (String an : node.getAttributes().keySet()) {
boolean ok = an.startsWith("xmlns") || Utilities.existsInList(an,
"title", "style", "class", "id", "lang", "xml:lang", "dir", "accesskey", "tabindex",
"title", "style", "class", ID, "lang", "xml:lang", "dir", "accesskey", "tabindex",
// tables
"span", "width", "align", "valign", "char", "charoff", "abbr", "axis", "headers", "scope", "rowspan", "colspan") ||
@ -2440,7 +2452,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
container.getNamedChildren("contained", contained);
for (int i = 0; i < contained.size(); i++) {
Element we = contained.get(i);
if (id.equals(we.getNamedChildValue("id"))) {
if (id.equals(we.getNamedChildValue(ID))) {
return new IndexedElement(i, we, null);
}
}
@ -2574,26 +2586,26 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
List<Element> entries = new ArrayList<Element>();
bundle.getNamedChildren("entry", entries);
bundle.getNamedChildren(ENTRY, entries);
Element match = null;
int matchIndex = -1;
for (int i = 0; i < entries.size(); i++) {
Element we = entries.get(i);
if (targetUrl.equals(we.getChildValue("fullUrl"))) {
Element r = we.getNamedChild("resource");
if (targetUrl.equals(we.getChildValue(FULL_URL))) {
Element r = we.getNamedChild(RESOURCE);
if (version.isEmpty()) {
rule(errors, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref);
match = r;
matchIndex = i;
} else {
try {
if (version.equals(r.getChildren("meta").get(0).getChildValue("versionId"))) {
if (version.equals(r.getChildren(META).get(0).getChildValue("versionId"))) {
rule(errors, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref);
match = r;
matchIndex = i;
}
} catch (Exception e) {
warning(errors, IssueType.REQUIRED, -1, -1, path, r.getChildren("meta").size() == 1 && r.getChildren("meta").get(0).getChildValue("versionId") != null, I18nConstants.BUNDLE_BUNDLE_FULLURL_NEEDVERSION, targetUrl);
warning(errors, IssueType.REQUIRED, -1, -1, path, r.getChildren(META).size() == 1 && r.getChildren(META).get(0).getChildValue("versionId") != null, I18nConstants.BUNDLE_BUNDLE_FULLURL_NEEDVERSION, targetUrl);
// If one of these things is null
}
}
@ -2703,12 +2715,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean isParametersEntry(String path) {
String[] parts = path.split("\\.");
return parts.length > 2 && parts[parts.length - 1].equals("resource") && (pathEntryHasName(parts[parts.length - 2], "parameter") || pathEntryHasName(parts[parts.length - 2], "part"));
return parts.length > 2 && parts[parts.length - 1].equals(RESOURCE) && (pathEntryHasName(parts[parts.length - 2], "parameter") || pathEntryHasName(parts[parts.length - 2], "part"));
}
private boolean isBundleEntry(String path) {
String[] parts = path.split("\\.");
return parts.length > 2 && parts[parts.length - 1].equals("resource") && pathEntryHasName(parts[parts.length - 2], "entry");
return parts.length > 2 && parts[parts.length - 1].equals(RESOURCE) && pathEntryHasName(parts[parts.length - 2], ENTRY);
}
private boolean isBundleOutcome(String path) {
@ -2798,15 +2810,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// the resource in the bundle
String fullUrl = null; // we're going to try to work this out as we go up
while (stack != null && stack.getElement() != null) {
if (stack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && stack.parent != null && stack.parent.getElement().getName().equals("entry")) {
String type = stack.parent.parent.element.getChildValue("type");
fullUrl = stack.parent.getElement().getChildValue("fullUrl"); // we don't try to resolve contained references across this boundary
if (stack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && stack.parent != null && stack.parent.getElement().getName().equals(ENTRY)) {
String type = stack.parent.parent.element.getChildValue(TYPE);
fullUrl = stack.parent.getElement().getChildValue(FULL_URL); // we don't try to resolve contained references across this boundary
if (fullUrl == null)
rule(errors, IssueType.REQUIRED, stack.parent.getElement().line(), stack.parent.getElement().col(), stack.parent.getLiteralPath(),
Utilities.existsInList(type, "batch-response", "transaction-response") || fullUrl != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFULLURL);
}
if ("Bundle".equals(stack.getElement().getType())) {
String type = stack.getElement().getChildValue("type");
if (BUNDLE.equals(stack.getElement().getType())) {
String type = stack.getElement().getChildValue(TYPE);
IndexedElement res = getFromBundle(stack.getElement(), ref, fullUrl, errors, path, type, "transaction".equals(type));
if (res == null) {
return null;
@ -2824,10 +2836,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
stack = stack.parent;
}
// we can get here if we got called via FHIRPath conformsTo which breaks the stack continuity.
if (hostContext != null && "Bundle".equals(hostContext.fhirType())) {
String type = hostContext.getChildValue("type");
if (hostContext != null && BUNDLE.equals(hostContext.fhirType())) {
String type = hostContext.getChildValue(TYPE);
Element entry = getEntryForSource(hostContext, source);
fullUrl = entry.getChildValue("fullUrl");
fullUrl = entry.getChildValue(FULL_URL);
IndexedElement res = getFromBundle(hostContext, ref, fullUrl, errors, path, type, "transaction".equals(type));
if (res == null) {
return null;
@ -2848,7 +2860,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Element getEntryForSource(Element bundle, Element element) {
List<Element> entries = new ArrayList<Element>();
bundle.getNamedChildren("entry", entries);
bundle.getNamedChildren(ENTRY, entries);
for (Element entry : entries) {
if (entry.hasDescendant(element)) {
return entry;
@ -2930,7 +2942,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (Utilities.isAbsoluteUrl(ref)) {
// if the reference is absolute, then you resolve by fullUrl. No other thinking is required.
for (Element entry : entries) {
String fu = entry.getNamedChildValue("fullUrl");
String fu = entry.getNamedChildValue(FULL_URL);
if (ref.equals(fu))
return entry;
}
@ -2947,14 +2959,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
String t = parts[0];
String i = parts[1];
for (Element entry : entries) {
String fu = entry.getNamedChildValue("fullUrl");
String fu = entry.getNamedChildValue(FULL_URL);
if (fu != null && fu.equals(u))
return entry;
if (u == null) {
Element resource = entry.getNamedChild("resource");
Element resource = entry.getNamedChild(RESOURCE);
if (resource != null) {
String et = resource.getType();
String eid = resource.getNamedChildValue("id");
String eid = resource.getNamedChildValue(ID);
if (t.equals(et) && i.equals(eid))
return entry;
}
@ -3218,7 +3230,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
first = false;
else
expression.append(" and ");
buildCodeableConceptExpression(ed, expression, "type", ii.getType());
buildCodeableConceptExpression(ed, expression, TYPE, ii.getType());
}
expression.append(").exists()");
}
@ -3330,13 +3342,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void start(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element resource, Element element, StructureDefinition defn, NodeStack stack) throws FHIRException {
checkLang(resource, stack);
if ("Bundle".equals(element.fhirType())) {
if (BUNDLE.equals(element.fhirType())) {
resolveBundleReferences(element, new ArrayList<Element>());
}
startInner(hostContext, errors, resource, element, defn, stack, hostContext.isCheckSpecials());
List<String> res = new ArrayList<>();
Element meta = element.getNamedChild("meta");
Element meta = element.getNamedChild(META);
if (meta != null) {
List<Element> profiles = new ArrayList<Element>();
meta.getNamedChildren("profile", profiles);
@ -3359,10 +3371,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
List<Element> list = new ArrayList<Element>();
list.addAll(bundles);
list.add(0, element);
List<Element> entries = element.getChildrenByName("entry");
List<Element> entries = element.getChildrenByName(ENTRY);
for (Element entry : entries) {
String fu = entry.getChildValue("fullUrl");
Element r = entry.getNamedChild("resource");
String fu = entry.getChildValue(FULL_URL);
Element r = entry.getNamedChild(RESOURCE);
if (r != null) {
resolveBundleReferencesInResource(list, r, fu);
}
@ -3372,7 +3384,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void resolveBundleReferencesInResource(List<Element> bundles, Element r, String fu) {
r.setUserData("validator.bundle.resolution-resource", null);
if ("Bundle".equals(r.fhirType())) {
if (BUNDLE.equals(r.fhirType())) {
resolveBundleReferences(r, bundles);
} else {
for (Element child : r.getChildren()) {
@ -3386,10 +3398,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
String ref = element.getChildValue("reference");
if (!Utilities.noString(ref)) {
for (Element bundle : bundles) {
List<Element> entries = bundle.getChildren("entry");
List<Element> entries = bundle.getChildren(ENTRY);
Element tgt = resolveInBundle(entries, ref, fu, resource.fhirType(), resource.getIdBase());
if (tgt != null) {
element.setUserData("validator.bundle.resolution", tgt.getNamedChild("resource"));
element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE));
return;
}
}
@ -3437,7 +3449,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public void checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials) {
// specific known special validations
if (element.getType().equals("Bundle")) {
if (element.getType().equals(BUNDLE)) {
validateBundle(errors, element, stack, checkSpecials);
} else if (element.getType().equals("Observation")) {
validateObservation(errors, element, stack);
@ -3586,7 +3598,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
// security tags are a set (system|code)
Element meta = element.getNamedChild("meta");
Element meta = element.getNamedChild(META);
if (meta != null) {
Set<String> tags = new HashSet<>();
List<Element> list = new ArrayList<>();
@ -3605,11 +3617,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
int iRest = 0;
for (Element rest : cs.getChildrenByName("rest")) {
int iResource = 0;
for (Element resource : rest.getChildrenByName("resource")) {
for (Element resource : rest.getChildrenByName(RESOURCE)) {
int iSP = 0;
for (Element searchParam : resource.getChildrenByName("searchParam")) {
String ref = searchParam.getChildValue("definition");
String type = searchParam.getChildValue("type");
String type = searchParam.getChildValue(TYPE);
if (!Utilities.noString(ref)) {
SearchParameter sp = context.fetchResource(SearchParameter.class, ref);
if (sp != null) {
@ -4213,32 +4225,35 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials) {
List<Element> entries = new ArrayList<Element>();
bundle.getNamedChildren("entry", entries);
String type = bundle.getNamedChildValue("type");
bundle.getNamedChildren(ENTRY, entries);
String type = bundle.getNamedChildValue(TYPE);
type = StringUtils.defaultString(type);
if (entries.size() == 0) {
rule(errors, IssueType.INVALID, stack.getLiteralPath(), !(type.equals("document") || type.equals("message")), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRST);
rule(errors, IssueType.INVALID, stack.getLiteralPath(), !(type.equals(DOCUMENT) || type.equals(MESSAGE)), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRST);
} else {
// Get the first entry, the MessageHeader
Element firstEntry = entries.get(0);
// Get the stack of the first entry
NodeStack firstStack = stack.push(firstEntry, 1, null, null);
String fullUrl = firstEntry.getNamedChildValue("fullUrl");
String fullUrl = firstEntry.getNamedChildValue(FULL_URL);
if (type.equals("document")) {
Element resource = firstEntry.getNamedChild("resource");
String id = resource.getNamedChildValue("id");
if (rule(errors, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath("entry", ":0"), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
if (type.equals(DOCUMENT)) {
Element resource = firstEntry.getNamedChild(RESOURCE);
String id = resource.getNamedChildValue(ID);
if (rule(errors, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
validateDocument(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id);
}
if (!VersionUtilities.isThisOrLater(FHIRVersion._4_0_1.getDisplay(), bundle.getProperty().getStructure().getFhirVersion().getDisplay())) {
handleSpecialCaseForLastUpdated(bundle, errors, stack);
}
checkAllInterlinked(errors, entries, stack, bundle, true);
}
if (type.equals("message")) {
Element resource = firstEntry.getNamedChild("resource");
String id = resource.getNamedChildValue("id");
if (rule(errors, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath("entry", ":0"), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
if (type.equals(MESSAGE)) {
Element resource = firstEntry.getNamedChild(RESOURCE);
String id = resource.getNamedChildValue(ID);
if (rule(errors, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
validateMessage(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id);
}
checkAllInterlinked(errors, entries, stack, bundle, VersionUtilities.isR5Ver(context.getVersion()));
@ -4247,18 +4262,39 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// validateResourceIds(errors, entries, stack);
}
for (Element entry : entries) {
String fullUrl = entry.getNamedChildValue("fullUrl");
String fullUrl = entry.getNamedChildValue(FULL_URL);
String url = getCanonicalURLForEntry(entry);
String id = getIdForEntry(entry);
if (url != null) {
if (!(!url.equals(fullUrl) || (url.matches(uriRegexForVersion()) && url.endsWith("/" + id))) && !isV3orV2Url(url))
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath("entry", ":0"), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id);
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath("entry", ":0"), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild("resource").fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl);
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id);
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild(RESOURCE).fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl);
}
// todo: check specials
}
}
/**
* As per outline for <a href=http://hl7.org/fhir/stu3/documents.html#content>Document Content</a>:
* <li>"The document date (mandatory). This is found in Bundle.meta.lastUpdated and identifies when the document bundle
* was assembled from the underlying resources"</li>
* <p></p>
* This check was not being done for release versions < r4.
* <p></p>
* Related JIRA ticket is <a href=https://jira.hl7.org/browse/FHIR-26544>FHIR-26544</a>
*
* @param bundle {@link org.hl7.fhir.r5.elementmodel}
* @param errors {@link List<ValidationMessage>}
* @param stack {@link NodeStack}
*/
private void handleSpecialCaseForLastUpdated(Element bundle, List<ValidationMessage> errors, NodeStack stack) {
boolean ok = bundle.hasChild(META)
&& bundle.getNamedChild(META).hasChild(LAST_UPDATED)
&& bundle.getNamedChild(META).getNamedChild(LAST_UPDATED).hasValue();
rule(errors, IssueType.REQUIRED, stack.addToLiteralPath(ENTRY, PATH_ARG), ok, "A document must have a date [(type = 'document') implies (meta.lastUpdated.hasValue())]");
}
// hack for pre-UTG v2/v3
private boolean isV3orV2Url(String url) {
return url.startsWith("http://hl7.org/fhir/v3/") || url.startsWith("http://hl7.org/fhir/v2/");
@ -4276,17 +4312,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
private String getCanonicalURLForEntry(Element entry) {
Element e = entry.getNamedChild("resource");
Element e = entry.getNamedChild(RESOURCE);
if (e == null)
return null;
return e.getNamedChildValue("url");
}
private String getIdForEntry(Element entry) {
Element e = entry.getNamedChild("resource");
Element e = entry.getNamedChild(RESOURCE);
if (e == null)
return null;
return e.getNamedChildValue("id");
return e.getNamedChildValue(ID);
}
/**
@ -4302,9 +4338,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// TODO: Need to handle _version
int i = 1;
for (Element entry : entries) {
String fullUrl = entry.getNamedChildValue("fullUrl");
Element resource = entry.getNamedChild("resource");
String id = resource != null ? resource.getNamedChildValue("id") : null;
String fullUrl = entry.getNamedChildValue(FULL_URL);
Element resource = entry.getNamedChild(RESOURCE);
String id = resource != null ? resource.getNamedChildValue(ID) : null;
if (id != null && fullUrl != null) {
String urlId = null;
if (fullUrl.startsWith("https://") || fullUrl.startsWith("http://")) {
@ -4321,7 +4357,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void checkAllInterlinked(List<ValidationMessage> errors, List<Element> entries, NodeStack stack, Element bundle, boolean isError) {
List<EntrySummary> entryList = new ArrayList<>();
for (Element entry : entries) {
Element r = entry.getNamedChild("resource");
Element r = entry.getNamedChild(RESOURCE);
if (r != null) {
entryList.add(new EntrySummary(entry, r));
}
@ -4329,7 +4365,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
for (EntrySummary e : entryList) {
Set<String> references = findReferences(e.getEntry());
for (String ref : references) {
Element tgt = resolveInBundle(entries, ref, e.getEntry().getChildValue("fullUrl"), e.getResource().fhirType(), e.getResource().getIdBase());
Element tgt = resolveInBundle(entries, ref, e.getEntry().getChildValue(FULL_URL), e.getResource().fhirType(), e.getResource().getIdBase());
if (tgt != null) {
EntrySummary t = entryForTarget(entryList, tgt);
if (t != null) {
@ -4364,9 +4400,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
for (EntrySummary e : entryList) {
Element entry = e.getEntry();
if (isError) {
rule(errors, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath("entry" + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN, (entry.getChildValue("fullUrl") != null ? "'" + entry.getChildValue("fullUrl") + "'" : ""));
rule(errors, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN, (entry.getChildValue(FULL_URL) != null ? "'" + entry.getChildValue(FULL_URL) + "'" : ""));
} else {
warning(errors, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath("entry" + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN, (entry.getChildValue("fullUrl") != null ? "'" + entry.getChildValue("fullUrl") + "'" : ""));
warning(errors, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN, (entry.getChildValue(FULL_URL) != null ? "'" + entry.getChildValue(FULL_URL) + "'" : ""));
}
i++;
}
@ -4395,17 +4431,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
private void followResourceLinks(Element entry, Map<String, Element> visitedResources, Map<Element, Element> candidateEntries, List<Element> candidateResources, List<ValidationMessage> errors, NodeStack stack, int depth) {
Element resource = entry.getNamedChild("resource");
Element resource = entry.getNamedChild(RESOURCE);
if (visitedResources.containsValue(resource))
return;
visitedResources.put(entry.getNamedChildValue("fullUrl"), resource);
visitedResources.put(entry.getNamedChildValue(FULL_URL), resource);
String type = null;
Set<String> references = findReferences(resource);
for (String reference : references) {
// We don't want errors when just retrieving the element as they will be caught (with better path info) in subsequent processing
IndexedElement r = getFromBundle(stack.getElement(), reference, entry.getChildValue("fullUrl"), new ArrayList<ValidationMessage>(), stack.addToLiteralPath("entry[" + candidateResources.indexOf(resource) + "]"), type, "transaction".equals(stack.getElement().getChildValue("type")));
IndexedElement r = getFromBundle(stack.getElement(), reference, entry.getChildValue(FULL_URL), new ArrayList<ValidationMessage>(), stack.addToLiteralPath("entry[" + candidateResources.indexOf(resource) + "]"), type, "transaction".equals(stack.getElement().getChildValue(TYPE)));
if (r != null && !visitedResources.containsValue(r.getMatch())) {
followResourceLinks(candidateEntries.get(r.getMatch()), visitedResources, candidateEntries, candidateResources, errors, stack, depth + 1);
}
@ -4981,8 +5017,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ed.hasSlicing()) {
if (slicer != null && slicer.getPath().equals(ed.getPath())) {
String errorContext = "profile " + profile.getUrl();
if (!resource.getChildValue("id").isEmpty())
errorContext += "; instance " + resource.getChildValue("id");
if (!resource.getChildValue(ID).isEmpty())
errorContext += "; instance " + resource.getChildValue(ID);
throw new DefinitionException(formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
}
slicer = ed;
@ -5114,7 +5150,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (isBundleEntry(ei.getPath())) {
Element req = ep.getNamedChild("request");
Element resp = ep.getNamedChild("response");
Element fullUrl = ep.getNamedChild("fullUrl");
Element fullUrl = ep.getNamedChild(FULL_URL);
Element method = null;
Element url = null;
if (req != null) {
@ -5268,7 +5304,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
String type = defn.getKind() == StructureDefinitionKind.LOGICAL ? defn.getId() : defn.getType();
// special case: we have a bundle, and the profile is not for a bundle. We'll try the first entry instead
if (!type.equals(resourceName) && resourceName.equals("Bundle")) {
if (!type.equals(resourceName) && resourceName.equals(BUNDLE)) {
NodeStack first = getFirstEntry(stack);
if (first != null && first.getElement().getType().equals(type)) {
element = first.element;
@ -5281,9 +5317,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
ok = rule(errors, IssueType.INVALID, -1, -1, stack.getLiteralPath(), type.equals(resourceName), I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE, type, resourceName);
if (ok) {
if (idstatus == IdStatus.REQUIRED && (element.getNamedChild("id") == null))
if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID) == null))
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_MISSING);
else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild("id") != null))
else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild(ID) != null))
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_PROHIBITED);
start(hostContext, errors, element, element, defn, stack); // root is both definition and type
}
@ -5291,10 +5327,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private NodeStack getFirstEntry(NodeStack bundle) {
List<Element> list = new ArrayList<Element>();
bundle.getElement().getNamedChildren("entry", list);
bundle.getElement().getNamedChildren(ENTRY, list);
if (list.isEmpty())
return null;
Element resource = list.get(0).getNamedChild("resource");
Element resource = list.get(0).getNamedChild(RESOURCE);
if (resource == null)
return null;
else {
@ -5315,7 +5351,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
validateDocumentReference(errors, entries, section, stack, fullUrl, id, false, "focus", "Section");
List<Element> sectionEntries = new ArrayList<Element>();
section.getNamedChildren("entry", sectionEntries);
section.getNamedChildren(ENTRY, sectionEntries);
int j = 1;
for (Element sectionEntry : sectionEntries) {
NodeStack localStack2 = localStack.push(sectionEntry, j, null, null);

View File

@ -66,7 +66,8 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
List<Object[]> objects = new ArrayList<Object[]>(examples.size());
for (String id : names) {
objects.add(new Object[] { id, examples.get(id)});
//if (id.equals("bundle-documentation-bad.json"))
objects.add(new Object[] { id, examples.get(id)});
}
return objects;
}

View File

@ -17,7 +17,7 @@
<properties>
<hapi_fhir_version>4.2.0</hapi_fhir_version>
<validator_test_case_version>1.0.46-SNAPSHOT</validator_test_case_version>
<validator_test_case_version>1.0.48-SNAPSHOT</validator_test_case_version>
</properties>
<artifactId>org.hl7.fhir.core</artifactId>