Changes related to validation of document and message links
This commit is contained in:
parent
7f35843440
commit
771fb0ac00
|
@ -837,6 +837,10 @@ public class ToolingExtensions {
|
|||
return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS));
|
||||
}
|
||||
|
||||
public static StandardsStatus getStandardsStatus(Element e) throws FHIRException {
|
||||
return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(e, ToolingExtensions.EXT_STANDARDS_STATUS));
|
||||
}
|
||||
|
||||
public static void setStandardsStatus(DomainResource dr, StandardsStatus status, String normativeVersion) {
|
||||
if (status == null)
|
||||
ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
|
||||
|
|
|
@ -29,8 +29,11 @@ public class I18nConstants {
|
|||
public static final String BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE = "Bundle_BUNDLE_Entry_NoProfile_TYPE";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_NOTFOUND = "Bundle_BUNDLE_Entry_NotFound";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_ORPHAN = "Bundle_BUNDLE_Entry_Orphan";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_REVERSE = "BUNDLE_BUNDLE_ENTRY_REVERSE";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_ORPHAN_DOCUMENT = "Bundle_BUNDLE_Entry_Orphan_DOCUMENT";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_ORPHAN_MESSAGE = "Bundle_BUNDLE_Entry_Orphan_MESSAGE";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_REVERSE_R4 = "BUNDLE_BUNDLE_ENTRY_REVERSE_R4";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_REVERSE_R5 = "BUNDLE_BUNDLE_ENTRY_REVERSE_R5";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_REVERSE_MSG = "BUNDLE_BUNDLE_ENTRY_REVERSE_MSG";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_TYPE = "Bundle_BUNDLE_Entry_Type";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_TYPE2 = "Bundle_BUNDLE_Entry_Type2";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_TYPE3 = "Bundle_BUNDLE_Entry_Type3";
|
||||
|
@ -38,6 +41,13 @@ public class I18nConstants {
|
|||
public static final String BUNDLE_BUNDLE_FULLURL_NEEDVERSION = "Bundle_BUNDLE_FullUrl_NeedVersion";
|
||||
public static final String BUNDLE_BUNDLE_MULTIPLEMATCHES = "Bundle_BUNDLE_MultipleMatches";
|
||||
public static final String BUNDLE_BUNDLE_NOT_LOCAL = "Bundle_BUNDLE_Not_Local";
|
||||
public static final String BUNDLE_LINK_UNKNOWN = "BUNDLE_LINK_UNKNOWN";
|
||||
public static final String BUNDLE_LINK_SEARCH_PROHIBITED = "BUNDLE_LINK_SEARCH_PROHIBITED";
|
||||
public static final String BUNDLE_LINK_SEARCH_NO_DUPLICATES = "BUNDLE_LINK_SEARCH_NO_DUPLICATES";
|
||||
public static final String BUNDLE_LINK_STYELSHEET_EXTERNAL = "BUNDLE_LINK_STYELSHEET_EXTERNAL";
|
||||
public static final String BUNDLE_LINK_STYELSHEET_INSECURE = "BUNDLE_LINK_STYELSHEET_INSECURE";
|
||||
public static final String BUNDLE_LINK_STYELSHEET_LINKABLE = "BUNDLE_LINK_STYELSHEET_LINKABLE";
|
||||
public static final String BUNDLE_LINK_STYELSHEET_NOT_FOUND = "BUNDLE_LINK_STYELSHEET_NOT_FOUND";
|
||||
public static final String BUNDLE_MSG_EVENT_COUNT = "Bundle_MSG_Event_Count";
|
||||
public static final String CANT_HAVE_CHILDREN_ON_AN_ELEMENT_WITH_A_POLYMORPHIC_TYPE__YOU_MUST_SLICE_AND_CONSTRAIN_THE_TYPES_FIRST_SORTELEMENTS_ = "Cant_have_children_on_an_element_with_a_polymorphic_type__you_must_slice_and_constrain_the_types_first_sortElements_";
|
||||
public static final String CAN_ONLY_SPECIFY_PROFILE_IN_THE_CONTEXT = "Can_only_specify_profile_in_the_context";
|
||||
|
|
|
@ -12,8 +12,11 @@ Bundle_BUNDLE_Entry_NoProfile_TYPE = No profile found for {0} resource of type '
|
|||
Bundle_BUNDLE_Entry_NoProfile_EXPL = Specified profile {2} not found for {0} resource of type ''{0}''
|
||||
Bundle_BUNDLE_Entry_NO_LOGICAL_EXPL = Specified logical model {1} not found for resource ''Binary/{0}''
|
||||
Bundle_BUNDLE_Entry_NotFound = Can''t find ''{0}'' in the bundle ({1})
|
||||
Bundle_BUNDLE_Entry_Orphan = Entry {0} isn''t reachable by traversing from first Bundle entry
|
||||
BUNDLE_BUNDLE_ENTRY_REVERSE = Entry {0} isn''t reachable by traversing forwards from first Bundle entry, and isn''t a resource type that is typically used that way - check this is not missed somewhere
|
||||
Bundle_BUNDLE_Entry_Orphan_MESSAGE = Entry {0} isn''t reachable by traversing links (forward or backward) from the MessageHeader, so it's presence should be reviewed (is it needed to process the message?)
|
||||
Bundle_BUNDLE_Entry_Orphan_DOCUMENT = Entry {0} isn''t reachable by traversing links (forward or backward) from the Composition
|
||||
BUNDLE_BUNDLE_ENTRY_REVERSE_R4 = Entry {0} isn''t reachable by traversing forwards from the Composition. Only Provenance is approved to be used this way (R4 section 3.3.1)
|
||||
BUNDLE_BUNDLE_ENTRY_REVERSE_R5 = Entry {0} isn''t reachable by traversing forwards from the Composition. Check whether this should be linked directly from the composition if it's a source of narrative content
|
||||
BUNDLE_BUNDLE_ENTRY_REVERSE_MSG = Entry {0} isn''t reachable by traversing forwards from the MessageHeader. Check that this is meant to be included (needed to process the message)
|
||||
Bundle_BUNDLE_Entry_Type = The type ''{0}'' is not valid - no resources allowed here (allowed = {1})
|
||||
Bundle_BUNDLE_Entry_Type2 = The type ''{0}'' is not valid - must be {1} (allowed = {2})
|
||||
Bundle_BUNDLE_Entry_Type3_one = The type ''{1}'' is not valid - must be of type {2}
|
||||
|
@ -23,7 +26,7 @@ Bundle_BUNDLE_FullUrl_NeedVersion = Entries matching fullURL {0} should declare
|
|||
Bundle_BUNDLE_MultipleMatches = Multiple matches in bundle for reference {0}
|
||||
Bundle_BUNDLE_Not_Local = URN reference is not locally contained within the bundle {0}
|
||||
Bundle_MSG_Event_Count = Expected {0} but found {1} event elements
|
||||
Bundle_Document_Date_Missing = A document must have a date
|
||||
Bundle_Document_Date_Missing = A document must have a date (Bundle.timestamp)
|
||||
Bundle_Document_Date_Missing_html = [(type = ''document'') implies (meta.lastUpdated.hasValue())]
|
||||
CapabalityStatement_CS_SP_WrongType = Type mismatch - SearchParameter ''{0}'' type is {1}, but type here is {2}
|
||||
CodeSystem_CS_VS_IncludeDetails = CodeSystem {0} has an ''all system'' value set of {1}, but the include has extra details
|
||||
|
@ -807,3 +810,10 @@ JSON_PROPERTY_VALUE_NO_QUOTES = The JSON property ''{0}'' has no quotes around t
|
|||
JSON_COMMA_MISSING = A Comma is missing in the JSON
|
||||
JSON_COMMA_EXTRA = There is an extra comma at the end of the {0} in the JSON
|
||||
JSON_COMMENTS_NOT_ALLOWED = Comments are not allowed in JSON
|
||||
BUNDLE_LINK_UNKNOWN = The link relationship type ''{0}'' is unknown and not allowed in this context
|
||||
BUNDLE_LINK_SEARCH_PROHIBITED = The link relationship type ''{0}'' used in search sets is prohibited in this context
|
||||
BUNDLE_LINK_SEARCH_NO_DUPLICATES = The link relationship type ''{0}'' can only occur once
|
||||
BUNDLE_LINK_STYELSHEET_EXTERNAL = External Stylesheets other than https://hl7.org/fhir/fhir.css SHOULD not be used
|
||||
BUNDLE_LINK_STYELSHEET_INSECURE = The stylesheet reference is not secure
|
||||
BUNDLE_LINK_STYELSHEET_LINKABLE = The stylesheet reference is not resolvable link
|
||||
BUNDLE_LINK_STYELSHEET_NOT_FOUND = The stylesheet reference could not be resolved in this bundle
|
||||
|
|
|
@ -44,11 +44,20 @@ public class BundleValidator extends BaseValidator {
|
|||
|
||||
public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidatorHostContext hostContext, PercentageTracker pct, ValidationMode mode) {
|
||||
boolean ok = true;
|
||||
List<Element> entries = new ArrayList<Element>();
|
||||
bundle.getNamedChildren(ENTRY, entries);
|
||||
String type = bundle.getNamedChildValue(TYPE);
|
||||
type = StringUtils.defaultString(type);
|
||||
List<Element> entries = new ArrayList<Element>();
|
||||
bundle.getNamedChildren(ENTRY, entries);
|
||||
|
||||
List<Element> links = new ArrayList<Element>();
|
||||
bundle.getNamedChildren(LINK, links);
|
||||
if (links.size() > 0) {
|
||||
int i = 0;
|
||||
for (Element l : links) {
|
||||
ok = validateLink(errors, bundle, links, l, stack.push(l, i++, null, null), type, entries) && ok;
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.size() == 0) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, stack.getLiteralPath(), !(type.equals(DOCUMENT) || type.equals(MESSAGE)), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRST) && ok;
|
||||
} else {
|
||||
|
@ -68,7 +77,7 @@ public class BundleValidator extends BaseValidator {
|
|||
if (!VersionUtilities.isThisOrLater(FHIRVersion._4_0_1.getDisplay(), bundle.getProperty().getStructure().getFhirVersion().getDisplay())) {
|
||||
ok = handleSpecialCaseForLastUpdated(bundle, errors, stack) && ok;
|
||||
}
|
||||
ok = checkAllInterlinked(errors, entries, stack, bundle, true) && ok;
|
||||
ok = checkAllInterlinked(errors, entries, stack, bundle, false) && ok;
|
||||
}
|
||||
if (type.equals(MESSAGE)) {
|
||||
Element resource = firstEntry.getNamedChild(RESOURCE);
|
||||
|
@ -76,7 +85,7 @@ public class BundleValidator extends BaseValidator {
|
|||
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
|
||||
ok = validateMessage(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok;
|
||||
}
|
||||
ok = checkAllInterlinked(errors, entries, stack, bundle, VersionUtilities.isR5Ver(context.getVersion())) && ok;
|
||||
ok = checkAllInterlinked(errors, entries, stack, bundle, true) && ok;
|
||||
}
|
||||
if (type.equals(SEARCHSET)) {
|
||||
checkSearchSet(errors, bundle, entries, stack);
|
||||
|
@ -133,6 +142,151 @@ public class BundleValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, String type, List<Element> entries) {
|
||||
switch (type) {
|
||||
case "document": return validateDocumentLink(errors, bundle, links, link, stack, entries);
|
||||
case "message": return validateMessageLink(errors, bundle, links, link, stack, entries);
|
||||
case "history":
|
||||
case "searchset": return validateSearchLink(errors, bundle, links, link, stack);
|
||||
case "collection": return validateCollectionLink(errors, bundle, links, link, stack);
|
||||
case "subscription-notification": return validateSubscriptionLink(errors, bundle, links, link, stack);
|
||||
case "transaction":
|
||||
case "transaction-response":
|
||||
case "batch":
|
||||
case "batch-response":
|
||||
return validateTransactionOrBatchLink(errors, bundle, links, link, stack);
|
||||
default:
|
||||
return true; // unknown document type, deal with that elsewhere
|
||||
}
|
||||
// rule(errors, "2022-12-09", IssueType.INVALID, l.line(), l.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_LINK_UNKNOWN, );
|
||||
}
|
||||
|
||||
private boolean validateDocumentLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) {
|
||||
boolean ok = true;
|
||||
Element relE = link.getNamedChild("relation");
|
||||
if (relE != null) {
|
||||
NodeStack relStack = stack.push(relE, -1, null, null);
|
||||
String rel = relE.getValue();
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), !Utilities.existsInList(rel, "first", "previous", "next", "last"), I18nConstants.BUNDLE_LINK_SEARCH_PROHIBITED, rel);
|
||||
if ("self".equals(rel)) {
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok;
|
||||
}
|
||||
if ("stylesheet".equals(rel)) {
|
||||
Element urlE = link.getNamedChild("url");
|
||||
if (urlE != null) {
|
||||
NodeStack urlStack = stack.push(urlE, -1, null, null);
|
||||
String url = urlE.getValue();
|
||||
if (url != null) {
|
||||
if (Utilities.isAbsoluteUrl(url)) {
|
||||
// todo: do we need to consider rel = base?
|
||||
if (url.equals("https://hl7.org/fhir/fhir.css")) {
|
||||
// well, this is ok!
|
||||
} else {
|
||||
warning(errors, "2022-12-09", IssueType.BUSINESSRULE, urlE.line(), urlE.col(), urlStack.getLiteralPath(), false, I18nConstants.BUNDLE_LINK_STYELSHEET_EXTERNAL);
|
||||
if (url.startsWith("http://")) {
|
||||
warning(errors, "2022-12-09", IssueType.BUSINESSRULE, urlE.line(), urlE.col(), urlStack.getLiteralPath(), false, I18nConstants.BUNDLE_LINK_STYELSHEET_INSECURE);
|
||||
}
|
||||
if (!Utilities.isAbsoluteUrlLinkable(url)) {
|
||||
warning(errors, "2022-12-09", IssueType.BUSINESSRULE, urlE.line(), urlE.col(), urlStack.getLiteralPath(), false, I18nConstants.BUNDLE_LINK_STYELSHEET_LINKABLE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// has to resolve in the bundle
|
||||
boolean found = false;
|
||||
for (Element e : entries) {
|
||||
Element res = e.getNamedChild("resource");
|
||||
if (res != null && (""+res.fhirType()+"/"+res.getIdBase()).equals(url)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok = rule(errors, "2022-12-09", IssueType.NOTFOUND, urlE.line(), urlE.col(), urlStack.getLiteralPath(), found, I18nConstants.BUNDLE_LINK_STYELSHEET_NOT_FOUND) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateMessageLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) {
|
||||
boolean ok = true;
|
||||
Element relE = link.getNamedChild("relation");
|
||||
if (relE != null) {
|
||||
NodeStack relStack = stack.push(relE, -1, null, null);
|
||||
String rel = relE.getValue();
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), !Utilities.existsInList(rel, "first", "previous", "next", "last"), I18nConstants.BUNDLE_LINK_SEARCH_PROHIBITED, rel);
|
||||
if ("self".equals(rel)) {
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateSearchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
|
||||
String rel = StringUtils.defaultString(link.getNamedChildValue("relation"));
|
||||
if (Utilities.existsInList(rel, "first", "previous", "next", "last", "self")) {
|
||||
return rule(errors, "2022-12-09", IssueType.INVALID, link.line(), link.col(), stack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean relationshipUnique(String rel, Element link, List<Element> links) {
|
||||
for (Element l : links) {
|
||||
if (l != link && rel.equals(l.getNamedChildValue("relation"))) {
|
||||
return false;
|
||||
}
|
||||
if (l == link) {
|
||||
// we only want to complain once, so we only look above this one
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean validateCollectionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
Element relE = link.getNamedChild("relation");
|
||||
if (relE != null) {
|
||||
NodeStack relStack = stack.push(relE, -1, null, null);
|
||||
String rel = relE.getValue();
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), !Utilities.existsInList(rel, "first", "previous", "next", "last"), I18nConstants.BUNDLE_LINK_SEARCH_PROHIBITED, rel);
|
||||
if ("self".equals(rel)) {
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateSubscriptionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
Element relE = link.getNamedChild("relation");
|
||||
if (relE != null) {
|
||||
NodeStack relStack = stack.push(relE, -1, null, null);
|
||||
String rel = relE.getValue();
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), !Utilities.existsInList(rel, "first", "previous", "next", "last"), I18nConstants.BUNDLE_LINK_SEARCH_PROHIBITED, rel);
|
||||
if ("self".equals(rel)) {
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean validateTransactionOrBatchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
|
||||
boolean ok = true;
|
||||
Element relE = link.getNamedChild("relation");
|
||||
if (relE != null) {
|
||||
NodeStack relStack = stack.push(relE, -1, null, null);
|
||||
String rel = relE.getValue();
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), !Utilities.existsInList(rel, "first", "previous", "next", "last"), I18nConstants.BUNDLE_LINK_SEARCH_PROHIBITED, rel);
|
||||
if ("self".equals(rel)) {
|
||||
ok = rule(errors, "2022-12-09", IssueType.INVALID, relE.line(), relE.col(), relStack.getLiteralPath(), relationshipUnique(rel, link, links), I18nConstants.BUNDLE_LINK_SEARCH_NO_DUPLICATES, rel) && ok;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private void checkSearchSet(List<ValidationMessage> errors, Element bundle, List<Element> entries, NodeStack stack) {
|
||||
// warning: should have self link
|
||||
List<Element> links = new ArrayList<Element>();
|
||||
|
@ -413,7 +567,7 @@ public class BundleValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkAllInterlinked(List<ValidationMessage> errors, List<Element> entries, NodeStack stack, Element bundle, boolean isError) {
|
||||
private boolean checkAllInterlinked(List<ValidationMessage> errors, List<Element> entries, NodeStack stack, Element bundle, boolean isMessage) {
|
||||
boolean ok = true;
|
||||
List<EntrySummary> entryList = new ArrayList<>();
|
||||
int i = 0;
|
||||
|
@ -447,6 +601,7 @@ public class BundleValidator extends BaseValidator {
|
|||
|
||||
Set<EntrySummary> visited = new HashSet<>();
|
||||
visitLinked(visited, entryList.get(0));
|
||||
visitBundleLinks(visited, entryList, bundle);
|
||||
boolean foundRevLinks;
|
||||
do {
|
||||
foundRevLinks = false;
|
||||
|
@ -460,10 +615,22 @@ public class BundleValidator extends BaseValidator {
|
|||
}
|
||||
}
|
||||
if (add) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, e.getEntry().line(), e.getEntry().col(),
|
||||
if (isMessage) {
|
||||
hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, e.getEntry().line(), e.getEntry().col(),
|
||||
stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), isExpectedToBeReverse(e.getResource().fhirType()),
|
||||
I18nConstants.BUNDLE_BUNDLE_ENTRY_REVERSE_MSG, (e.getEntry().getChildValue(FULL_URL) != null ? "'" + e.getEntry().getChildValue(FULL_URL) + "'" : ""));
|
||||
} else {
|
||||
// this was illegal up to R4B, but changed to be legal in R5
|
||||
if (VersionUtilities.isR5VerOrLater(context.getVersion())) {
|
||||
hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, e.getEntry().line(), e.getEntry().col(),
|
||||
stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), isExpectedToBeReverse(e.getResource().fhirType()),
|
||||
I18nConstants.BUNDLE_BUNDLE_ENTRY_REVERSE_R4, (e.getEntry().getChildValue(FULL_URL) != null ? "'" + e.getEntry().getChildValue(FULL_URL) + "'" : ""));
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INVALID, e.getEntry().line(), e.getEntry().col(),
|
||||
stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), isExpectedToBeReverse(e.getResource().fhirType()),
|
||||
I18nConstants.BUNDLE_BUNDLE_ENTRY_REVERSE, (e.getEntry().getChildValue(FULL_URL) != null ? "'" + e.getEntry().getChildValue(FULL_URL) + "'" : ""));
|
||||
// System.out.println("Found reverse links for "+e.getIndex());
|
||||
I18nConstants.BUNDLE_BUNDLE_ENTRY_REVERSE_R4, (e.getEntry().getChildValue(FULL_URL) != null ? "'" + e.getEntry().getChildValue(FULL_URL) + "'" : ""));
|
||||
}
|
||||
}
|
||||
foundRevLinks = true;
|
||||
visitLinked(visited, e);
|
||||
}
|
||||
|
@ -474,10 +641,10 @@ public class BundleValidator extends BaseValidator {
|
|||
i = 0;
|
||||
for (EntrySummary e : entryList) {
|
||||
Element entry = e.getEntry();
|
||||
if (isError) {
|
||||
ok = rule(errors, NO_RULE_DATE, 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) + "'" : "")) && ok;
|
||||
if (isMessage) {
|
||||
warning(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN_MESSAGE, (entry.getChildValue(FULL_URL) != null ? "'" + entry.getChildValue(FULL_URL) + "'" : ""));
|
||||
} else {
|
||||
warning(errors, NO_RULE_DATE, 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) + "'" : ""));
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY + '[' + (i + 1) + ']'), visited.contains(e), I18nConstants.BUNDLE_BUNDLE_ENTRY_ORPHAN_DOCUMENT, (entry.getChildValue(FULL_URL) != null ? "'" + entry.getChildValue(FULL_URL) + "'" : "")) && ok;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -486,6 +653,26 @@ public class BundleValidator extends BaseValidator {
|
|||
|
||||
|
||||
|
||||
private void visitBundleLinks(Set<EntrySummary> visited, List<EntrySummary> entryList, Element bundle) {
|
||||
List<Element> links = bundle.getChildrenByName("link");
|
||||
for (Element link : links) {
|
||||
String rel = link.getNamedChildValue("relation");
|
||||
String url = link.getNamedChildValue("url");
|
||||
if (rel != null && url != null) {
|
||||
if (Utilities.existsInList(rel, "stylesheet")) {
|
||||
for (EntrySummary e : entryList) {
|
||||
if (e.getResource() != null) {
|
||||
if (url.equals(e.getResource().fhirType()+"/"+e.getResource().getIdBase())) {
|
||||
visited.add(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExpectedToBeReverse(String fhirType) {
|
||||
return Utilities.existsInList(fhirType, "Provenance");
|
||||
}
|
||||
|
|
|
@ -2068,3 +2068,12 @@ v: {
|
|||
"system" : "http://snomed.info/sct"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"code" : "text/css"
|
||||
}, "url": "http://hl7.org/fhir/ValueSet/mimetypes", "version": "4.0.1", "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"true", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}####
|
||||
v: {
|
||||
"display" : "text/css",
|
||||
"code" : "text/css",
|
||||
"system" : "urn:ietf:bcp:13"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue