Merge pull request #1489 from hapifhir/2023-11-gg-bundle-link-validation

Rework bundle references validation
This commit is contained in:
Grahame Grieve 2023-11-15 20:09:31 +11:00 committed by GitHub
commit 2efb34c66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 650 additions and 554 deletions

View File

@ -685,13 +685,16 @@ public class Element extends Base implements NamedItem {
} }
public Element getNamedChild(String name) { public Element getNamedChild(String name) {
return getNamedChild(name, true);
}
public Element getNamedChild(String name, boolean exception) {
if (children == null) if (children == null)
return null; return null;
if (children.size() > 20) { if (children.size() > 20) {
List<Element> l = children.getByName(name); List<Element> l = children.getByName(name);
if (l == null || l.size() == 0) { if (l == null || l.size() == 0) {
// try the other way (in case of complicated naming rules) // try the other way (in case of complicated naming rules)
} else if (l.size() > 1) { } else if (l.size() > 1 && exception) {
throw new Error("Attempt to read a single element when there is more than one present ("+name+")"); throw new Error("Attempt to read a single element when there is more than one present ("+name+")");
} else { } else {
return l.get(0); return l.get(0);
@ -729,7 +732,11 @@ public class Element extends Base implements NamedItem {
} }
public String getNamedChildValue(String name) { public String getNamedChildValue(String name) {
Element child = getNamedChild(name); return getNamedChildValue(name, true);
}
public String getNamedChildValue(String name, boolean exception) {
Element child = getNamedChild(name, exception);
return child == null ? null : child.value; return child == null ? null : child.value;
} }
@ -781,7 +788,11 @@ public class Element extends Base implements NamedItem {
} }
public boolean hasChild(String name) { public boolean hasChild(String name) {
return getNamedChild(name) != null; return getNamedChild(name, true) != null;
}
public boolean hasChild(String name, boolean exception) {
return getNamedChild(name, exception) != null;
} }
public boolean hasChildren(String name) { public boolean hasChildren(String name) {
@ -1019,15 +1030,15 @@ public class Element extends Base implements NamedItem {
return c; return c;
} else if ("Coding".equals(fhirType())) { } else if ("Coding".equals(fhirType())) {
ICodingImpl c = new ICodingImpl(true, true, true, true); ICodingImpl c = new ICodingImpl(true, true, true, true);
c.system = getNamedChildValue("system"); c.system = getNamedChildValue("system", false);
c.code = getNamedChildValue("code"); c.code = getNamedChildValue("code", false);
c.display = getNamedChildValue("display"); c.display = getNamedChildValue("display", false);
c.version = getNamedChildValue("version"); c.version = getNamedChildValue("version", false);
return c; return c;
} else if ("Quantity".equals(fhirType())) { } else if ("Quantity".equals(fhirType())) {
ICodingImpl c = new ICodingImpl(true, true, false, false); ICodingImpl c = new ICodingImpl(true, true, false, false);
c.system = getNamedChildValue("system"); c.system = getNamedChildValue("system", false);
c.code = getNamedChildValue("code"); c.code = getNamedChildValue("code", false);
return c; return c;
} else } else
return null; return null;
@ -1072,7 +1083,7 @@ public class Element extends Base implements NamedItem {
if (Utilities.existsInList(child.getName(), "extension", "modifierExtension")) { if (Utilities.existsInList(child.getName(), "extension", "modifierExtension")) {
String u = child.getChildValue("url"); String u = child.getChildValue("url");
if (url.equals(u)) { if (url.equals(u)) {
return child.getNamedChild("value"); return child.getNamedChild("value", false);
} }
} }
} }
@ -1324,7 +1335,7 @@ public class Element extends Base implements NamedItem {
for (Property p : property.getChildProperties(this.name, type)) { for (Property p : property.getChildProperties(this.name, type)) {
if (p.getName().equals(name)) { if (p.getName().equals(name)) {
if (!p.isList() && hasChild(name)) { if (!p.isList() && hasChild(name, false)) {
throw new Error(name+" on "+this.name+" is not a list, so can't add an element"); throw new Error(name+" on "+this.name+" is not a list, so can't add an element");
} }
Element ne = new Element(name, p).setFormat(format); Element ne = new Element(name, p).setFormat(format);
@ -1412,17 +1423,17 @@ public class Element extends Base implements NamedItem {
public String getTranslation(String lang) { public String getTranslation(String lang) {
for (Element e : getChildren()) { for (Element e : getChildren()) {
if (e.fhirType().equals("Extension")) { if (e.fhirType().equals("Extension")) {
String url = e.getNamedChildValue("url"); String url = e.getNamedChildValue("url", false);
if (ToolingExtensions.EXT_TRANSLATION.equals(url)) { if (ToolingExtensions.EXT_TRANSLATION.equals(url)) {
String l = null; String l = null;
String v = null; String v = null;
for (Element g : e.getChildren()) { for (Element g : e.getChildren()) {
if (g.fhirType().equals("Extension")) { if (g.fhirType().equals("Extension")) {
String u = g.getNamedChildValue("url"); String u = g.getNamedChildValue("url", false);
if ("lang".equals(u)) { if ("lang".equals(u)) {
l = g.getNamedChildValue("value"); l = g.getNamedChildValue("value", false);
} else if ("value".equals(u)) { } else if ("value".equals(u)) {
v = g.getNamedChildValue("value"); v = g.getNamedChildValue("value", false);
} }
} }
} }
@ -1451,17 +1462,17 @@ public class Element extends Base implements NamedItem {
public void setTranslation(String lang, String translation) { public void setTranslation(String lang, String translation) {
for (Element e : getChildren()) { for (Element e : getChildren()) {
if (e.fhirType().equals("Extension")) { if (e.fhirType().equals("Extension")) {
String url = e.getNamedChildValue("url"); String url = e.getNamedChildValue("url", false);
if (ToolingExtensions.EXT_TRANSLATION.equals(url)) { if (ToolingExtensions.EXT_TRANSLATION.equals(url)) {
String l = null; String l = null;
Element v = null; Element v = null;
for (Element g : e.getChildren()) { for (Element g : e.getChildren()) {
if (g.fhirType().equals("Extension")) { if (g.fhirType().equals("Extension")) {
String u = g.getNamedChildValue("url"); String u = g.getNamedChildValue("url", false);
if ("lang".equals(u)) { if ("lang".equals(u)) {
l = g.getNamedChildValue("value"); l = g.getNamedChildValue("value", false);
} else if ("value".equals(u)) { } else if ("value".equals(u)) {
v = g.getNamedChild("value"); v = g.getNamedChild("value", false);
} }
} }
} }

View File

@ -358,7 +358,7 @@ public abstract class ResourceRenderer extends DataRenderer {
org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version); org.hl7.fhir.r5.elementmodel.Element bundleElement = rcontext.resolveElement(url, version);
if (bundleElement != null) { if (bundleElement != null) {
String bundleUrl = null; String bundleUrl = null;
Element br = bundleElement.getNamedChild("resource"); Element br = bundleElement.getNamedChild("resource", false);
if (br.getChildValue("id") != null) { if (br.getChildValue("id") != null) {
bundleUrl = "#" + br.fhirType() + "_" + br.getChildValue("id"); bundleUrl = "#" + br.fhirType() + "_" + br.getChildValue("id");
} else { } else {

View File

@ -1026,6 +1026,7 @@ public class I18nConstants {
public static final String BUNDLE_ENTRY_URL_MATCHES_TYPE_ID = "BUNDLE_ENTRY_URL_MATCHES_TYPE_ID"; public static final String BUNDLE_ENTRY_URL_MATCHES_TYPE_ID = "BUNDLE_ENTRY_URL_MATCHES_TYPE_ID";
public static final String BUNDLE_ENTRY_URL_MATCHES_NO_ID = "BUNDLE_ENTRY_URL_MATCHES_NO_ID"; public static final String BUNDLE_ENTRY_URL_MATCHES_NO_ID = "BUNDLE_ENTRY_URL_MATCHES_NO_ID";
public static final String BUNDLE_ENTRY_URL_ABSOLUTE = "BUNDLE_ENTRY_URL_ABSOLUTE"; public static final String BUNDLE_ENTRY_URL_ABSOLUTE = "BUNDLE_ENTRY_URL_ABSOLUTE";
public static final String BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = "BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE";
} }

View File

@ -12,7 +12,9 @@ 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_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_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_NotFound = Can''t find ''{0}'' in the bundle ({1})
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT = Can''t find ''{0}'' in the bundle ({1}). Note that there is a resource in the bundle with the same type and id, but it does not match because of the fullUrl based rules around matching relative resources BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = Found {0} matches for ''{1}'' in the bundle ({2})
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_one = Can''t find ''{1}'' in the bundle ({2}). Note that there is a resource in the bundle with the same type and id, but it does not match because of the fullUrl based rules around matching relative references (must be ``{3}``)
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_other = Can''t find ''{1}'' in the bundle ({2}). Note that there are {0} resources in the bundle with the same type and id, but they do not match because of the fullUrl based rules around matching relative references (one of ``{3}``)
Bundle_BUNDLE_Entry_Orphan_MESSAGE = Entry {0} isn''t reachable by traversing links (forward or backward) from the MessageHeader, so its presence should be reviewed (is it needed to process the message?) Bundle_BUNDLE_Entry_Orphan_MESSAGE = Entry {0} isn''t reachable by traversing links (forward or backward) from the MessageHeader, so its 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_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_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)

View File

@ -837,3 +837,6 @@ SD_ED_TYPE_PROFILE_WRONG_TYPE_other =
VALUESET_SUPPLEMENT_MISSING_one = VALUESET_SUPPLEMENT_MISSING_one =
VALUESET_SUPPLEMENT_MISSING_many = VALUESET_SUPPLEMENT_MISSING_many =
VALUESET_SUPPLEMENT_MISSING_other = VALUESET_SUPPLEMENT_MISSING_other =
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_one =
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_many =
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_other =

View File

@ -12,6 +12,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.naming.Context;
import org.antlr.v4.codegen.model.decl.ContextTokenGetterDecl;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
All rights reserved. All rights reserved.
@ -79,33 +83,12 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.validation.BaseValidator.ElementMatch;
import org.hl7.fhir.validation.cli.utils.ValidationLevel; import org.hl7.fhir.validation.cli.utils.ValidationLevel;
import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.IndexedElement;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
public class BaseValidator implements IValidationContextResourceLoader { public class BaseValidator implements IValidationContextResourceLoader {
public class ElementMatch {
private Element element;
private boolean valid;
protected ElementMatch(Element element, boolean valid) {
super();
this.element = element;
this.valid = valid;
}
public Element getElement() {
return element;
}
public boolean isValid() {
return valid;
}
}
public class BooleanHolder { public class BooleanHolder {
private boolean value = true; private boolean value = true;
@ -488,6 +471,10 @@ public class BaseValidator implements IValidationContextResourceLoader {
return thePass; return thePass;
} }
protected boolean rulePlural(List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack node, boolean thePass, int num, String theMessage, Object... theMessageArguments) {
return rulePlural(errors, ruleDate, type, node.line(), node.col(), node.getLiteralPath(), thePass, num, theMessage, theMessageArguments);
}
protected boolean rulePlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) { protected boolean rulePlural(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, int num, String theMessage, Object... theMessageArguments) {
if (!thePass && doingErrors()) { if (!thePass && doingErrors()) {
String message = context.formatMessagePlural(num, theMessage, theMessageArguments); String message = context.formatMessagePlural(num, theMessage, theMessageArguments);
@ -771,6 +758,10 @@ public class BaseValidator implements IValidationContextResourceLoader {
trackedMessages.removeAll(messages); trackedMessages.removeAll(messages);
} }
protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String msg, Object... theMessageArguments) {
return warningOrError(isError, errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), thePass, msg, theMessageArguments);
}
protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
String nmsg = context.formatMessage(msg, theMessageArguments); String nmsg = context.formatMessage(msg, theMessageArguments);
@ -783,6 +774,22 @@ public class BaseValidator implements IValidationContextResourceLoader {
} }
protected boolean hintOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, NodeStack stack, boolean thePass, String msg, Object... theMessageArguments) {
return hintOrError(isError, errors, ruleDate, type, stack.line(), stack.col(), stack.getLiteralPath(), thePass, msg, theMessageArguments);
}
protected boolean hintOrError(boolean isError, List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
if (!thePass) {
String nmsg = context.formatMessage(msg, theMessageArguments);
IssueSeverity lvl = isError ? IssueSeverity.ERROR : IssueSeverity.INFORMATION;
if (doingLevel(lvl)) {
addValidationMessage(errors, ruleDate, type, line, col, path, nmsg, lvl, msg);
}
}
return thePass;
}
/** /**
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
* *
@ -1010,7 +1017,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
return null; return null;
if (bnd.fhirType().equals(BUNDLE)) { if (bnd.fhirType().equals(BUNDLE)) {
for (Element be : bnd.getChildrenByName(ENTRY)) { for (Element be : bnd.getChildrenByName(ENTRY)) {
Element res = be.getNamedChild(RESOURCE); Element res = be.getNamedChild(RESOURCE, false);
if (res != null) { if (res != null) {
String fullUrl = be.getChildValue(FULL_URL); String fullUrl = be.getChildValue(FULL_URL);
String rt = res.fhirType(); String rt = res.fhirType();
@ -1025,28 +1032,42 @@ public class BaseValidator implements IValidationContextResourceLoader {
return null; return null;
} }
protected ElementMatch resolveInBundle(Element bundle, List<Element> entries, String ref, String fullUrl, String type, String id) { protected Element resolveInBundle(Element bundle, List<Element> entries, String ref, String fullUrl, String type, String id, NodeStack stack, List<ValidationMessage> errors, String name, Element source, boolean isWarning) {
if ("MedicationStatement/d41ac499-c7e8-45fa-9246-69028bae178f".equals(ref)) {
System.out.println("!");
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Element> map = (Map<String, Element>) bundle.getUserData("validator.entrymap"); Map<String, List<Element>> map = (Map<String, List<Element>>) bundle.getUserData("validator.entrymap");
Map<String, Element> relMap = (Map<String, Element>) bundle.getUserData("validator.entrymapR"); @SuppressWarnings("unchecked")
Map<String, List<Element>> relMap = (Map<String, List<Element>>) bundle.getUserData("validator.entrymapR");
List<Element> list = null;
if (map == null) { if (map == null) {
map = new HashMap<>(); map = new HashMap<>();
bundle.setUserData("validator.entrymap", map); bundle.setUserData("validator.entrymap", map);
relMap = new HashMap<>(); relMap = new HashMap<>();
bundle.setUserData("validator.entrymapR", relMap); bundle.setUserData("validator.entrymapR", relMap);
for (Element entry : entries) { for (Element entry : entries) {
String fu = entry.getNamedChildValue(FULL_URL); String fu = entry.getNamedChildValue(FULL_URL, false);
map.put(fu, entry); list = map.get(fu);
Element resource = entry.getNamedChild(RESOURCE); if (list == null) {
list = new ArrayList<Element>();
map.put(fu, list);
}
list.add(entry);
Element resource = entry.getNamedChild(RESOURCE, false);
if (resource != null) { if (resource != null) {
String et = resource.getType(); String et = resource.getType();
String eid = resource.getNamedChildValue(ID); String eid = resource.getNamedChildValue(ID, false);
if (eid != null) { if (eid != null) {
if (VersionUtilities.isR4Plus(context.getVersion())) { String rl = et+"/"+eid;
relMap.put(et+"/"+eid, entry); list = relMap.get(rl);
} else { if (list == null) {
map.put(et+"/"+eid, entry); list = new ArrayList<Element>();
relMap.put(rl, list);
} }
list.add(entry);
} }
} }
} }
@ -1054,62 +1075,89 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (Utilities.isAbsoluteUrl(ref)) { if (Utilities.isAbsoluteUrl(ref)) {
// if the reference is absolute, then you resolve by fullUrl. No other thinking is required. // if the reference is absolute, then you resolve by fullUrl. No other thinking is required.
Element e = map.get(ref); List<Element> el = map.get(ref);
if (e == null) { if (el == null) {
// if this something we complain about?
// not if it's in a package, or it looks like a restful URL and it's one of the canonical resource types
boolean ok = context.hasResource(Resource.class, ref);
if (!ok && ref.matches(urlRegex)) {
String tt = extractResourceType(ref);
ok = VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(tt);
}
if (!ok && stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name);
}
return null; return null;
} else if (el.size() == 1) {
return el.get(0);
} else { } else {
return new ElementMatch(e, true); if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name);
}
return null;
} }
// for (Element entry : entries) {
// String fu = entry.getNamedChildValue(FULL_URL);
// if (ref.equals(fu))
// return entry;
// }
// return null;
} else { } else {
// split into base, type, and id // split into base, type, and id
String u = null; String u = null;
if (fullUrl != null && fullUrl.matches(urlRegex) && fullUrl.endsWith(type + "/" + id)) { if (fullUrl != null && fullUrl.matches(urlRegex) && fullUrl.endsWith(type + "/" + id)) {
// fullUrl = complex
u = fullUrl.substring(0, fullUrl.length() - (type + "/" + id).length()) + ref; u = fullUrl.substring(0, fullUrl.length() - (type + "/" + id).length()) + ref;
} }
// u = fullUrl.substring((type+"/"+id).length())+ref; List<Element> el = map.get(u);
String[] parts = ref.split("\\/"); if (el != null && el.size() > 0) {
if (parts.length >= 2) { if (el.size() == 1) {
String t = parts[0]; return el.get(0);
String i = parts[1];
Element res = map.get(u);
if (res == null) {
res = map.get(t+"/"+i);
}
if (res == null && relMap.containsKey(t+"/"+i)) {
res = relMap.get(t+"/"+i);
return new ElementMatch(res, false);
} else if (res == null) {
return null;
} else { } else {
return new ElementMatch(res, true); if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name);
}
return null;
} }
// for (Element entry : entries) { } else {
// String fu = entry.getNamedChildValue(FULL_URL); String[] parts = ref.split("\\/");
// if (fu != null && fu.equals(u)) if (parts.length >= 2) {
// return entry; String t = parts[0];
// if (u == null) { if (context.getResourceNamesAsSet().contains(t)) {
// Element resource = entry.getNamedChild(RESOURCE); String i = parts[1];
// if (resource != null) { el = relMap.get(t+"/"+i);
// String et = resource.getType(); if (el != null) {
// String eid = resource.getNamedChildValue(ID); Set<String> tl = new HashSet<>();
// if (t.equals(et) && i.equals(eid)) for (Element e : el) {
// return entry; String fu = e.getNamedChildValue(FULL_URL, false);
// } tl.add(fu == null ? "<missing>" : fu);
// } }
// } if (!VersionUtilities.isR4Plus(context.getVersion())) {
if (el.size() == 1) {
return el.get(0);
} else if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl)));
}
} else if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl)));
}
} else {
if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name);
}
}
}
}
return null;
} }
return null;
} }
} }
private String extractResourceType(String ref) {
String[] p = ref.split("\\/");
return p[p.length -2];
}
protected IndexedElement getFromBundle(Element bundle, String ref, String fullUrl, List<ValidationMessage> errors, String path, String type, boolean isTransaction, BooleanHolder bh) { protected IndexedElement getFromBundle(Element bundle, String ref, String fullUrl, List<ValidationMessage> errors, String path, String type, boolean isTransaction, BooleanHolder bh) {
String targetUrl = null; String targetUrl = null;
String version = ""; String version = "";
@ -1173,7 +1221,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
Element we = entries.get(i); Element we = entries.get(i);
if (targetUrl.equals(we.getChildValue(FULL_URL))) { if (targetUrl.equals(we.getChildValue(FULL_URL))) {
Element r = we.getNamedChild(RESOURCE); Element r = we.getNamedChild(RESOURCE, false);
if (version.isEmpty()) { if (version.isEmpty()) {
rule(errors, NO_RULE_DATE, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref); rule(errors, NO_RULE_DATE, IssueType.FORBIDDEN, -1, -1, path, match == null, I18nConstants.BUNDLE_BUNDLE_MULTIPLEMATCHES, ref);
match = r; match = r;
@ -1203,8 +1251,8 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (p.length >= 2 && context.getResourceNamesAsSet().contains(p[0]) && Utilities.isValidId(p[1])) { if (p.length >= 2 && context.getResourceNamesAsSet().contains(p[0]) && Utilities.isValidId(p[1])) {
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
Element we = entries.get(i); Element we = entries.get(i);
Element r = we.getNamedChild(RESOURCE); Element r = we.getNamedChild(RESOURCE, false);
if (r != null && p[0].equals(r.fhirType()) && p[1].equals(r.getNamedChildValue("id")) ) { if (r != null && p[0].equals(r.fhirType()) && p[1].equals(r.getNamedChildValue("id", false)) ) {
ml.add(we); ml.add(we);
} }
} }

View File

@ -968,7 +968,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus().getBytes()), cnt.getCntType()); org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus().getBytes()), cnt.getCntType());
// if the src has a url, we try to use the java code // if the src has a url, we try to use the java code
if ((canDoNative == null && src.hasChild("url")) || (canDoNative != null && canDoNative)) { if ((canDoNative == null && src.hasChild("url", false)) || (canDoNative != null && canDoNative)) {
try { try {
if (VersionUtilities.isR2Ver(version)) { if (VersionUtilities.isR2Ver(version)) {
return VersionConvertor.convertVersionNativeR2(targetVer, cnt, format); return VersionConvertor.convertVersionNativeR2(targetVer, cnt, format);

View File

@ -1054,12 +1054,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkAddress(List<ValidationMessage> errors, String path, Element focus, Address fixed, String fixedSource, boolean pattern) { private boolean checkAddress(List<ValidationMessage> errors, String path, Element focus, Address fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".city", focus.getNamedChild("city"), fixed.getCityElement(), fixedSource, "city", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".city", focus.getNamedChild("city", false), fixed.getCityElement(), fixedSource, "city", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".state", focus.getNamedChild("state"), fixed.getStateElement(), fixedSource, "state", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".state", focus.getNamedChild("state", false), fixed.getStateElement(), fixedSource, "state", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".country", focus.getNamedChild("country"), fixed.getCountryElement(), fixedSource, "country", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".country", focus.getNamedChild("country", false), fixed.getCountryElement(), fixedSource, "country", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".zip", focus.getNamedChild("zip"), fixed.getPostalCodeElement(), fixedSource, "postalCode", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".zip", focus.getNamedChild("zip", false), fixed.getPostalCodeElement(), fixedSource, "postalCode", focus, pattern) && ok;
List<Element> lines = new ArrayList<Element>(); List<Element> lines = new ArrayList<Element>();
focus.getNamedChildren("line", lines); focus.getNamedChildren("line", lines);
@ -1106,13 +1106,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkAttachment(List<ValidationMessage> errors, String path, Element focus, Attachment fixed, String fixedSource, boolean pattern) { private boolean checkAttachment(List<ValidationMessage> errors, String path, Element focus, Attachment fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".contentType", focus.getNamedChild("contentType"), fixed.getContentTypeElement(), fixedSource, "contentType", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".contentType", focus.getNamedChild("contentType", false), fixed.getContentTypeElement(), fixedSource, "contentType", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".language", focus.getNamedChild("language"), fixed.getLanguageElement(), fixedSource, "language", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".language", focus.getNamedChild("language", false), fixed.getLanguageElement(), fixedSource, "language", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data"), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data", false), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".url", focus.getNamedChild("url"), fixed.getUrlElement(), fixedSource, "url", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".url", focus.getNamedChild("url", false), fixed.getUrlElement(), fixedSource, "url", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".size", focus.getNamedChild("size"), fixed.getSizeElement(), fixedSource, "size", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".size", focus.getNamedChild("size", false), fixed.getSizeElement(), fixedSource, "size", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".hash", focus.getNamedChild("hash"), fixed.getHashElement(), fixedSource, "hash", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".hash", focus.getNamedChild("hash", false), fixed.getHashElement(), fixedSource, "hash", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".title", focus.getNamedChild("title"), fixed.getTitleElement(), fixedSource, "title", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".title", focus.getNamedChild("title", false), fixed.getTitleElement(), fixedSource, "title", focus, pattern) && ok;
return ok; return ok;
} }
@ -1280,7 +1280,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkCodeableConcept(List<ValidationMessage> errors, String path, Element focus, CodeableConcept fixed, String fixedSource, boolean pattern) { private boolean checkCodeableConcept(List<ValidationMessage> errors, String path, Element focus, CodeableConcept fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern) && ok;
List<Element> codings = new ArrayList<Element>(); List<Element> codings = new ArrayList<Element>();
focus.getNamedChildren("coding", codings); focus.getNamedChildren("coding", codings);
if (pattern) { if (pattern) {
@ -1733,14 +1733,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) { private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) {
boolean ok = true; boolean ok = true;
cc.setText(element.getNamedChildValue("originalText")); cc.setText(element.getNamedChildValue("originalText", false));
if (element.hasChild("nullFlavor")) { if (element.hasChild("nullFlavor", false)) {
cc.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor", new CodeType(element.getNamedChildValue("nullFlavor"))); cc.addExtension("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor", new CodeType(element.getNamedChildValue("nullFlavor", false)));
} }
if (element.hasChild("code") || element.hasChild("codeSystem")) { if (element.hasChild("code", false) || element.hasChild("codeSystem", false)) {
Coding c = cc.addCoding(); Coding c = cc.addCoding();
String oid = element.getNamedChildValue("codeSystem"); String oid = element.getNamedChildValue("codeSystem", false);
if (oid != null) { if (oid != null) {
Set<String> urls = context.urlsForOid(true, oid); Set<String> urls = context.urlsForOid(true, oid);
if (urls.size() != 1) { if (urls.size() != 1) {
@ -1758,9 +1758,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
} }
c.setCode(element.getNamedChildValue("code")); c.setCode(element.getNamedChildValue("code", false));
c.setVersion(element.getNamedChildValue("codeSystemVersion")); c.setVersion(element.getNamedChildValue("codeSystemVersion", false));
c.setDisplay(element.getNamedChildValue("displayName")); c.setDisplay(element.getNamedChildValue("displayName", false));
} }
// todo: translations // todo: translations
return ok; return ok;
@ -1920,22 +1920,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkCoding(List<ValidationMessage> errors, String path, Element focus, Coding fixed, String fixedSource, boolean pattern) { private boolean checkCoding(List<ValidationMessage> errors, String path, Element focus, Coding fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".version", focus.getNamedChild("version"), fixed.getVersionElement(), fixedSource, "version", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".version", focus.getNamedChild("version", false), fixed.getVersionElement(), fixedSource, "version", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code"), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code", false), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display"), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display", false), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".userSelected", focus.getNamedChild("userSelected"), fixed.getUserSelectedElement(), fixedSource, "userSelected", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".userSelected", focus.getNamedChild("userSelected", false), fixed.getUserSelectedElement(), fixedSource, "userSelected", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkCoding(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack) { private boolean checkCoding(List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack) {
String code = element.getNamedChildValue("code"); String code = element.getNamedChildValue("code", false);
String system = element.getNamedChildValue("system"); String system = element.getNamedChildValue("system", false);
if (code != null && system == null) { if (code != null && system == null) {
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
} }
String version = element.getNamedChildValue("version"); String version = element.getNamedChildValue("version", false);
String display = element.getNamedChildValue("display"); String display = element.getNamedChildValue("display", false);
return checkCodedElement(errors, path, element, profile, theElementCntext, inCodeableConcept, checkDisplay, stack, code, system, version, display); return checkCodedElement(errors, path, element, profile, theElementCntext, inCodeableConcept, checkDisplay, stack, code, system, version, display);
} }
@ -2051,16 +2051,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkContactPoint(List<ValidationMessage> errors, String path, Element focus, ContactPoint fixed, String fixedSource, boolean pattern) { private boolean checkContactPoint(List<ValidationMessage> errors, String path, Element focus, ContactPoint fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkExtension(ValidationContext valContext, List<ValidationMessage> errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { private boolean checkExtension(ValidationContext valContext, List<ValidationMessage> errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException {
boolean ok = true; boolean ok = true;
String url = element.getNamedChildValue("url"); String url = element.getNamedChildValue("url", false);
String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url; String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url;
boolean isModifier = element.getName().equals("modifierExtension"); boolean isModifier = element.getName().equals("modifierExtension");
assert def.getIsModifier() == isModifier; assert def.getIsModifier() == isModifier;
@ -2262,10 +2262,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (stack.getElement().getName().startsWith("value")) { if (stack.getElement().getName().startsWith("value")) {
NodeStack estack = stack.getParent(); NodeStack estack = stack.getParent();
if (estack != null && estack.getElement().fhirType().equals("Extension")) { if (estack != null && estack.getElement().fhirType().equals("Extension")) {
ext = estack.getElement().getNamedChildValue("url"); ext = estack.getElement().getNamedChildValue("url", false);
} }
} else { } else {
ext = stack.getElement().getNamedChildValue("url"); ext = stack.getElement().getNamedChildValue("url", false);
} }
if (ctxt.getExpression().equals(ext)) { if (ctxt.getExpression().equals(ext)) {
ok = true; ok = true;
@ -2496,7 +2496,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
for (Extension e : fixed.getExtension()) { for (Extension e : fixed.getExtension()) {
Element ex = getExtensionByUrl(extensions, e.getUrl()); Element ex = getExtensionByUrl(extensions, e.getUrl());
if (rule(errors, NO_RULE_DATE, IssueType.VALUE, focus.line(), focus.col(), path, ex != null, I18nConstants.EXTENSION_EXT_COUNT_NOTFOUND, e.getUrl())) { if (rule(errors, NO_RULE_DATE, IssueType.VALUE, focus.line(), focus.col(), path, ex != null, I18nConstants.EXTENSION_EXT_COUNT_NOTFOUND, e.getUrl())) {
ok = checkFixedValue(errors, path, ex.getNamedChild("extension").getNamedChild("value"), e.getValue(), fixedSource, "extension.value", ex.getNamedChild("extension"), false) && ok; ok = checkFixedValue(errors, path, ex.getNamedChild("extension", false).getNamedChild("value", false), e.getValue(), fixedSource, "extension.value", ex.getNamedChild("extension", false), false) && ok;
} else { } else {
ok = false; ok = false;
} }
@ -2510,9 +2510,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkHumanName(List<ValidationMessage> errors, String path, Element focus, HumanName fixed, String fixedSource, boolean pattern) { private boolean checkHumanName(List<ValidationMessage> errors, String path, Element focus, HumanName fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern); ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern);
ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), fixedSource, "text", focus, pattern); ok = checkFixedValue(errors, path + ".text", focus.getNamedChild("text", false), fixed.getTextElement(), fixedSource, "text", focus, pattern);
ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern); ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern);
List<Element> parts = new ArrayList<Element>(); List<Element> parts = new ArrayList<Element>();
if (!pattern || fixed.hasFamily()) { if (!pattern || fixed.hasFamily()) {
@ -2556,10 +2556,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkIdentifier(List<ValidationMessage> errors, String path, Element element, ElementDefinition context) { private boolean checkIdentifier(List<ValidationMessage> errors, String path, Element element, ElementDefinition context) {
boolean ok = true; boolean ok = true;
String system = element.getNamedChildValue("system"); String system = element.getNamedChildValue("system", false);
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, system == null || isIdentifierSystemReferenceValid(system), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_SYSTEM) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, system == null || isIdentifierSystemReferenceValid(system), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_SYSTEM) && ok;
if ("urn:ietf:rfc:3986".equals(system)) { if ("urn:ietf:rfc:3986".equals(system)) {
String value = element.getNamedChildValue("value"); String value = element.getNamedChildValue("value", false);
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, value == null || isAbsolute(value), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_IETF_SYSTEM_VALUE, value) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, value == null || isAbsolute(value), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_IDENTIFIER_IETF_SYSTEM_VALUE, value) && ok;
} }
return ok; return ok;
@ -2567,19 +2567,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkIdentifier(List<ValidationMessage> errors, String path, Element focus, Identifier fixed, String fixedSource, boolean pattern) { private boolean checkIdentifier(List<ValidationMessage> errors, String path, Element focus, Identifier fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use"), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".use", focus.getNamedChild("use", false), fixed.getUseElement(), fixedSource, "use", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".type", focus.getNamedChild(TYPE), fixed.getType(), fixedSource, TYPE, focus, pattern) && ok; ok = checkFixedValue(errors, path + ".type", focus.getNamedChild(TYPE, false), fixed.getType(), fixedSource, TYPE, focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getPeriod(), fixedSource, "period", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".assigner", focus.getNamedChild("assigner"), fixed.getAssigner(), fixedSource, "assigner", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".assigner", focus.getNamedChild("assigner", false), fixed.getAssigner(), fixedSource, "assigner", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkPeriod(List<ValidationMessage> errors, String path, Element focus, Period fixed, String fixedSource, boolean pattern) { private boolean checkPeriod(List<ValidationMessage> errors, String path, Element focus, Period fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".start", focus.getNamedChild("start"), fixed.getStartElement(), fixedSource, "start", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".start", focus.getNamedChild("start", false), fixed.getStartElement(), fixedSource, "start", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), fixedSource, "end", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".end", focus.getNamedChild("end", false), fixed.getEndElement(), fixedSource, "end", focus, pattern) && ok;
return ok; return ok;
} }
@ -3409,20 +3409,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkQuantity(List<ValidationMessage> errors, String path, Element focus, Quantity fixed, String fixedSource, boolean pattern) { private boolean checkQuantity(List<ValidationMessage> errors, String path, Element focus, Quantity fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value"), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".value", focus.getNamedChild("value", false), fixed.getValueElement(), fixedSource, "value", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator"), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".comparator", focus.getNamedChild("comparator", false), fixed.getComparatorElement(), fixedSource, "comparator", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".unit", focus.getNamedChild("unit"), fixed.getUnitElement(), fixedSource, "unit", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".unit", focus.getNamedChild("unit", false), fixed.getUnitElement(), fixedSource, "unit", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system"), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".system", focus.getNamedChild("system", false), fixed.getSystemElement(), fixedSource, "system", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code"), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".code", focus.getNamedChild("code", false), fixed.getCodeElement(), fixedSource, "code", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkQuantity(List<ValidationMessage> errors, String path, Element element, StructureDefinition theProfile, ElementDefinition definition, NodeStack theStack) { private boolean checkQuantity(List<ValidationMessage> errors, String path, Element element, StructureDefinition theProfile, ElementDefinition definition, NodeStack theStack) {
boolean ok = true; boolean ok = true;
String value = element.hasChild("value") ? element.getNamedChild("value").getValue() : null; String value = element.hasChild("value", false) ? element.getNamedChild("value", false).getValue() : null;
String unit = element.hasChild("unit") ? element.getNamedChild("unit").getValue() : null; String unit = element.hasChild("unit", false) ? element.getNamedChild("unit", false).getValue() : null;
String system = element.hasChild("system") ? element.getNamedChild("system").getValue() : null; String system = element.hasChild("system", false) ? element.getNamedChild("system", false).getValue() : null;
String code = element.hasChild("code") ? element.getNamedChild("code").getValue() : null; String code = element.hasChild("code", false) ? element.getNamedChild("code", false).getValue() : null;
// todo: allowedUnits http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits - codeableConcept, or canonical(ValueSet) // todo: allowedUnits http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits - codeableConcept, or canonical(ValueSet)
// todo: http://hl7.org/fhir/StructureDefinition/iso21090-PQ-translation // todo: http://hl7.org/fhir/StructureDefinition/iso21090-PQ-translation
@ -3575,17 +3575,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
long size = -1; long size = -1;
// first check size // first check size
String fetchError = null; String fetchError = null;
if (element.hasChild("data")) { if (element.hasChild("data", false)) {
String b64 = element.getChildValue("data"); String b64 = element.getChildValue("data");
// Note: If the value isn't valid, we're not adding an error here, as the test to the // Note: If the value isn't valid, we're not adding an error here, as the test to the
// child Base64Binary will catch it and we don't want to log it twice // child Base64Binary will catch it and we don't want to log it twice
boolean bok = isValidBase64(b64); boolean bok = isValidBase64(b64);
if (bok && element.hasChild("size")) { if (bok && element.hasChild("size", false)) {
size = countBase64DecodedBytes(b64); size = countBase64DecodedBytes(b64);
String sz = element.getChildValue("size"); String sz = element.getChildValue("size");
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Long.toString(size).equals(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_CORRECT, sz, size) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Long.toString(size).equals(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_CORRECT, sz, size) && ok;
} }
} else if (element.hasChild("size")) { } else if (element.hasChild("size", false)) {
String sz = element.getChildValue("size"); String sz = element.getChildValue("size");
if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Utilities.isLong(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID, sz)) { if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, Utilities.isLong(sz), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_SIZE_INVALID, sz)) {
size = Long.parseLong(sz); size = Long.parseLong(sz);
@ -3593,7 +3593,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else { } else {
ok = false; ok = false;
} }
} else if (element.hasChild("url")) { } else if (element.hasChild("url", false)) {
String url = element.getChildValue("url"); String url = element.getChildValue("url");
if (definition.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) { if (definition.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) {
try { try {
@ -3620,7 +3620,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_TOO_LONG, size, def) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, size <= def, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_TOO_LONG, size, def) && ok;
} }
} }
warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, (element.hasChild("data") || element.hasChild("url")) || (element.hasChild("contentType") || element.hasChild("language")), warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, (element.hasChild("data", false) || element.hasChild("url", false)) || (element.hasChild("contentType", false) || element.hasChild("language", false)),
I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_NO_CONTENT); I18nConstants.TYPE_SPECIFIC_CHECKS_DT_ATT_NO_CONTENT);
return ok; return ok;
} }
@ -3629,15 +3629,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkRange(List<ValidationMessage> errors, String path, Element focus, Range fixed, String fixedSource, boolean pattern) { private boolean checkRange(List<ValidationMessage> errors, String path, Element focus, Range fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".low", focus.getNamedChild("low"), fixed.getLow(), fixedSource, "low", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".low", focus.getNamedChild("low", false), fixed.getLow(), fixedSource, "low", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".high", focus.getNamedChild("high"), fixed.getHigh(), fixedSource, "high", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".high", focus.getNamedChild("high", false), fixed.getHigh(), fixedSource, "high", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkRatio(List<ValidationMessage> errors, String path, Element focus, Ratio fixed, String fixedSource, boolean pattern) { private boolean checkRatio(List<ValidationMessage> errors, String path, Element focus, Ratio fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".numerator", focus.getNamedChild("numerator"), fixed.getNumerator(), fixedSource, "numerator", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".numerator", focus.getNamedChild("numerator", false), fixed.getNumerator(), fixedSource, "numerator", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".denominator", focus.getNamedChild("denominator"), fixed.getDenominator(), fixedSource, "denominator", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".denominator", focus.getNamedChild("denominator", false), fixed.getDenominator(), fixedSource, "denominator", focus, pattern) && ok;
return ok; return ok;
} }
@ -3657,7 +3657,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (!path.contains("element.pattern")) { // this business rule doesn't apply to patterns if (!path.contains("element.pattern")) { // this business rule doesn't apply to patterns
if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) { if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) {
warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path,
!Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY); !Utilities.noString(element.getNamedChildValue("display", false)), I18nConstants.REFERENCE_REF_NODISPLAY);
} }
} }
return true; return true;
@ -4034,33 +4034,33 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkSampledData(List<ValidationMessage> errors, String path, Element focus, SampledData fixed, String fixedSource, boolean pattern) { private boolean checkSampledData(List<ValidationMessage> errors, String path, Element focus, SampledData fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".origin", focus.getNamedChild("origin"), fixed.getOrigin(), fixedSource, "origin", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".origin", focus.getNamedChild("origin", false), fixed.getOrigin(), fixedSource, "origin", focus, pattern) && ok;
if (VersionUtilities.isR5VerOrLater(context.getVersion())) { if (VersionUtilities.isR5VerOrLater(context.getVersion())) {
ok = checkFixedValue(errors, path + ".interval", focus.getNamedChild("period"), fixed.getIntervalElement(), fixedSource, "interval", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".interval", focus.getNamedChild("period", false), fixed.getIntervalElement(), fixedSource, "interval", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".intervalUnit", focus.getNamedChild("period"), fixed.getIntervalUnitElement(), fixedSource, "intervalUnit", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".intervalUnit", focus.getNamedChild("period", false), fixed.getIntervalUnitElement(), fixedSource, "intervalUnit", focus, pattern) && ok;
} else { } else {
ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period"), fixed.getIntervalElement(), fixedSource, "period", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".period", focus.getNamedChild("period", false), fixed.getIntervalElement(), fixedSource, "period", focus, pattern) && ok;
} }
ok = checkFixedValue(errors, path + ".factor", focus.getNamedChild("factor"), fixed.getFactorElement(), fixedSource, "factor", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".factor", focus.getNamedChild("factor", false), fixed.getFactorElement(), fixedSource, "factor", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".lowerLimit", focus.getNamedChild("lowerLimit"), fixed.getLowerLimitElement(), fixedSource, "lowerLimit", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".lowerLimit", focus.getNamedChild("lowerLimit", false), fixed.getLowerLimitElement(), fixedSource, "lowerLimit", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".upperLimit", focus.getNamedChild("upperLimit"), fixed.getUpperLimitElement(), fixedSource, "upperLimit", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".upperLimit", focus.getNamedChild("upperLimit", false), fixed.getUpperLimitElement(), fixedSource, "upperLimit", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".dimensions", focus.getNamedChild("dimensions"), fixed.getDimensionsElement(), fixedSource, "dimensions", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".dimensions", focus.getNamedChild("dimensions", false), fixed.getDimensionsElement(), fixedSource, "dimensions", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data"), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".data", focus.getNamedChild("data", false), fixed.getDataElement(), fixedSource, "data", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkReference(List<ValidationMessage> errors, String path, Element focus, Reference fixed, String fixedSource, boolean pattern) { private boolean checkReference(List<ValidationMessage> errors, String path, Element focus, Reference fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".reference", focus.getNamedChild("reference"), fixed.getReferenceElement_(), fixedSource, "reference", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".reference", focus.getNamedChild("reference", false), fixed.getReferenceElement_(), fixedSource, "reference", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".type", focus.getNamedChild("type"), fixed.getTypeElement(), fixedSource, "type", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".type", focus.getNamedChild("type", false), fixed.getTypeElement(), fixedSource, "type", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".identifier", focus.getNamedChild("identifier"), fixed.getIdentifier(), fixedSource, "identifier", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".identifier", focus.getNamedChild("identifier", false), fixed.getIdentifier(), fixedSource, "identifier", focus, pattern) && ok;
ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display"), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".display", focus.getNamedChild("display", false), fixed.getDisplayElement(), fixedSource, "display", focus, pattern) && ok;
return ok; return ok;
} }
private boolean checkTiming(List<ValidationMessage> errors, String path, Element focus, Timing fixed, String fixedSource, boolean pattern) { private boolean checkTiming(List<ValidationMessage> errors, String path, Element focus, Timing fixed, String fixedSource, boolean pattern) {
boolean ok = true; boolean ok = true;
ok = checkFixedValue(errors, path + ".repeat", focus.getNamedChild("repeat"), fixed.getRepeat(), fixedSource, "value", focus, pattern) && ok; ok = checkFixedValue(errors, path + ".repeat", focus.getNamedChild("repeat", false), fixed.getRepeat(), fixedSource, "value", focus, pattern) && ok;
List<Element> events = new ArrayList<Element>(); List<Element> events = new ArrayList<Element>();
focus.getNamedChildren("event", events); focus.getNamedChildren("event", events);
@ -4157,7 +4157,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
container.getNamedChildren("contained", contained); container.getNamedChildren("contained", contained);
for (int i = 0; i < contained.size(); i++) { for (int i = 0; i < contained.size(); i++) {
Element we = contained.get(i); Element we = contained.get(i);
if (id.equals(we.getNamedChildValue(ID))) { if (id.equals(we.getNamedChildValue(ID, false))) {
return new IndexedElement(i, we, null); return new IndexedElement(i, we, null);
} }
} }
@ -4235,7 +4235,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Element getExtensionByUrl(List<Element> extensions, String urlSimple) { private Element getExtensionByUrl(List<Element> extensions, String urlSimple) {
for (Element e : extensions) { for (Element e : extensions) {
if (urlSimple.equals(e.getNamedChildValue("url"))) if (urlSimple.equals(e.getNamedChildValue("url", false)))
return e; return e;
} }
return null; return null;
@ -4556,8 +4556,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
int i = 0; int i = 0;
for (Element child : params.getElement().getChildren("parameter")) { for (Element child : params.getElement().getChildren("parameter")) {
NodeStack p = params.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition()); NodeStack p = params.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition());
if (child.hasChild("resource")) { if (child.hasChild("resource", false)) {
Element res = child.getNamedChild("resource"); Element res = child.getNamedChild("resource", false);
if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) { if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) {
return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition()); return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition());
} }
@ -4574,8 +4574,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
int i = 0; int i = 0;
for (Element child : param.getChildren("part")) { for (Element child : param.getChildren("part")) {
NodeStack p = pp.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition()); NodeStack p = pp.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition());
if (child.hasChild("resource")) { if (child.hasChild("resource", false)) {
Element res = child.getNamedChild("resource"); Element res = child.getNamedChild("resource", false);
if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) { if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) {
return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition()); return p.push(res, -1, res.getProperty().getDefinition(), res.getProperty().getDefinition());
} }
@ -5216,7 +5216,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
Element meta = element.getNamedChild(META); Element meta = element.getNamedChild(META, false);
if (meta != null) { if (meta != null) {
List<Element> profiles = new ArrayList<Element>(); List<Element> profiles = new ArrayList<Element>();
meta.getNamedChildren("profile", profiles); meta.getNamedChildren("profile", profiles);
@ -5361,7 +5361,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
List<Element> entries = element.getChildrenByName(ENTRY); List<Element> entries = element.getChildrenByName(ENTRY);
for (Element entry : entries) { for (Element entry : entries) {
String fu = entry.getChildValue(FULL_URL); String fu = entry.getChildValue(FULL_URL);
Element r = entry.getNamedChild(RESOURCE); Element r = entry.getNamedChild(RESOURCE, false);
if (r != null) { if (r != null) {
resolveBundleReferencesInResource(list, r, fu); resolveBundleReferencesInResource(list, r, fu);
} }
@ -5385,9 +5385,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (!Utilities.noString(ref)) { if (!Utilities.noString(ref)) {
for (Element bundle : bundles) { for (Element bundle : bundles) {
List<Element> entries = bundle.getChildren(ENTRY); List<Element> entries = bundle.getChildren(ENTRY);
ElementMatch tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase()); Element tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase(), null, null, null, element, false);
if (tgt != null && tgt.isValid()) { if (tgt != null) {
element.setUserData("validator.bundle.resolution", tgt.getElement().getNamedChild(RESOURCE)); element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE, false));
return; return;
} }
} }
@ -5443,7 +5443,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) { if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS); Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS);
String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null; String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null;
String status = element.getNamedChildValue("status"); String status = element.getNamedChildValue("status", false);
if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) { if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) {
if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) { if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) {
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus);
@ -5499,14 +5499,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkPublisherConsistency(List<ValidationMessage> errors, Element element, NodeStack stack) { private boolean checkPublisherConsistency(List<ValidationMessage> errors, Element element, NodeStack stack) {
String pub = element.getNamedChildValue("publisher"); 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();
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")) {
if ("url".equals(t.getNamedChildValue("system")) && t.getNamedChildValue("value") != null) { if ("url".equals(t.getNamedChildValue("system", false)) && t.getNamedChildValue("value", false) != null) {
urls.add(t.getNamedChildValue("value")); urls.add(t.getNamedChildValue("value", false));
} }
} }
} }
@ -5561,17 +5561,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
private void checkLang(Element resource, NodeStack stack) { private void checkLang(Element resource, NodeStack stack) {
String lang = resource.getNamedChildValue("language"); String lang = resource.getNamedChildValue("language", false);
if (!Utilities.noString(lang)) if (!Utilities.noString(lang))
stack.setWorkingLang(lang); stack.setWorkingLang(lang);
} }
private boolean validateResourceRules(List<ValidationMessage> errors, Element element, NodeStack stack) { private boolean validateResourceRules(List<ValidationMessage> errors, Element element, NodeStack stack) {
boolean ok= true; boolean ok= true;
String lang = element.getNamedChildValue("language"); String lang = element.getNamedChildValue("language", false);
Element text = element.getNamedChild("text"); Element text = element.getNamedChild("text", false);
if (text != null) { if (text != null) {
Element div = text.getNamedChild("div"); Element div = text.getNamedChild("div", false);
if (lang != null && div != null) { if (lang != null && div != null) {
XhtmlNode xhtml = div.getXhtml(); XhtmlNode xhtml = div.getXhtml();
String l = xhtml.getAttribute("lang"); String l = xhtml.getAttribute("lang");
@ -5593,14 +5593,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
} }
// security tags are a set (system|code) // security tags are a set (system|code)
Element meta = element.getNamedChild(META); Element meta = element.getNamedChild(META, false);
if (meta != null) { if (meta != null) {
Set<String> tags = new HashSet<>(); Set<String> tags = new HashSet<>();
List<Element> list = new ArrayList<>(); List<Element> list = new ArrayList<>();
meta.getNamedChildren("security", list); meta.getNamedChildren("security", list);
int i = 0; int i = 0;
for (Element e : list) { for (Element e : list) {
String s = e.getNamedChildValue("system") + "#" + e.getNamedChildValue("code"); String s = e.getNamedChildValue("system", false) + "#" + e.getNamedChildValue("code", false);
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, e.line(), e.col(), stack.getLiteralPath() + ".meta.profile[" + Integer.toString(i) + "]", !tags.contains(s), I18nConstants.META_RES_SECURITY_DUPLICATE, s) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, e.line(), e.col(), stack.getLiteralPath() + ".meta.profile[" + Integer.toString(i) + "]", !tags.contains(s), I18nConstants.META_RES_SECURITY_DUPLICATE, s) && ok;
tags.add(s); tags.add(s);
i++; i++;
@ -5903,10 +5903,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_PROFILE_STYLE) && "cda".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE))) { if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_PROFILE_STYLE) && "cda".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE))) {
List<Element> templates = element.getChildren("templateId"); List<Element> templates = element.getChildren("templateId");
for (Element t : templates) { for (Element t : templates) {
String tid = t.hasChild("extension") ? "urn:hl7ii:"+t.getChildValue("root")+ ":"+t.getChildValue("extension") : "urn:oid:"+t.getChildValue("root"); String tid = t.hasChild("extension", false) ? "urn:hl7ii:"+t.getChildValue("root")+ ":"+t.getChildValue("extension") : "urn:oid:"+t.getChildValue("root");
StructureDefinition sd = cu.fetchProfileByIdentifier(tid); StructureDefinition sd = cu.fetchProfileByIdentifier(tid);
if (sd == null) { if (sd == null) {
hint(errors, "2023-10-20", IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, t.hasChild("extension") ? I18nConstants.CDA_UNKNOWN_TEMPLATE_EXT : I18nConstants.CDA_UNKNOWN_TEMPLATE, t.getChildValue("root"), t.getChildValue("extension")); hint(errors, "2023-10-20", IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, t.hasChild("extension", false) ? I18nConstants.CDA_UNKNOWN_TEMPLATE_EXT : I18nConstants.CDA_UNKNOWN_TEMPLATE, t.getChildValue("root"), t.getChildValue("extension"));
} else { } else {
ElementDefinition ed = sd.getSnapshot().getElementFirstRep(); ElementDefinition ed = sd.getSnapshot().getElementFirstRep();
if (!element.hasValidated(sd, ed)) { if (!element.hasValidated(sd, ed)) {
@ -6152,7 +6152,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
ok = checkReference(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack, pct, mode) && ok; ok = checkReference(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, actualType, localStack, pct, mode) && ok;
// We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension // We only check extensions if we're not in a complex extension or if the element we're dealing with is not defined as part of that complex extension
} else if (type.equals("Extension")) { } else if (type.equals("Extension")) {
Element eurl = ei.getElement().getNamedChild("url"); Element eurl = ei.getElement().getNamedChild("url", false);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.getPath(), eurl != null, I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, ei.getPath(), eurl != null, I18nConstants.EXTENSION_EXT_URL_NOTFOUND)) {
String url = eurl.primitiveValue(); String url = eurl.primitiveValue();
thisExtension = url; thisExtension = url;
@ -6178,7 +6178,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (defn != null && defn.hasExtension(ToolingExtensions.EXT_BINDING_STYLE)) { if (defn != null && defn.hasExtension(ToolingExtensions.EXT_BINDING_STYLE)) {
String style = ToolingExtensions.readStringExtension(defn, ToolingExtensions.EXT_BINDING_STYLE); String style = ToolingExtensions.readStringExtension(defn, ToolingExtensions.EXT_BINDING_STYLE);
if ("CDA".equals(style)) { if ("CDA".equals(style)) {
if (!ei.getElement().hasChild("nullFlavor")) { if (!ei.getElement().hasChild("nullFlavor", false)) {
if (cdaTypeIs(defn, "CS")) { if (cdaTypeIs(defn, "CS")) {
ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok; ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
} else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) { } else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) {
@ -6299,8 +6299,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkCDACoding(List<ValidationMessage> errors, String path, boolean isPQ, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn, boolean inCodeableConcept, boolean checkDisplay) { private boolean checkCDACoding(List<ValidationMessage> errors, String path, boolean isPQ, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn, boolean inCodeableConcept, boolean checkDisplay) {
boolean ok = true; boolean ok = true;
String system = null; String system = null;
String code = element.getNamedChildValue(isPQ ? "unit" : "code"); String code = element.getNamedChildValue(isPQ ? "unit" : "code", false);
String oid = isPQ ? "2.16.840.1.113883.6.8" : element.getNamedChildValue("codeSystem"); String oid = isPQ ? "2.16.840.1.113883.6.8" : element.getNamedChildValue("codeSystem", false);
if (oid != null) { if (oid != null) {
Set<String> urls = context.urlsForOid(true, oid); Set<String> urls = context.urlsForOid(true, oid);
if (urls.size() != 1) { if (urls.size() != 1) {
@ -6319,14 +6319,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, code == null, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, code == null, I18nConstants.TERMINOLOGY_TX_SYSTEM_NO_CODE);
} }
String version = element.getNamedChildValue("codeSystemVersion"); String version = element.getNamedChildValue("codeSystemVersion", false);
String display = element.getNamedChildValue("displayName"); String display = element.getNamedChildValue("displayName", false);
return checkCodedElement(errors, path, element, profile, checkDefn, inCodeableConcept, checkDisplay, stack, code, system, version, display) && ok; return checkCodedElement(errors, path, element, profile, checkDefn, inCodeableConcept, checkDisplay, stack, code, system, version, display) && ok;
} }
private boolean checkCDACodeSimple(ValidationContext valContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn) { private boolean checkCDACodeSimple(ValidationContext valContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition checkDefn, NodeStack stack, StructureDefinition defn) {
if (element.hasChild("code")) { if (element.hasChild("code", false)) {
return checkPrimitiveBinding(valContext, errors, path, "code", checkDefn, element.getNamedChild("code"), profile, stack); return checkPrimitiveBinding(valContext, errors, path, "code", checkDefn, element.getNamedChild("code", false), profile, stack);
} else { } else {
return false; return false;
} }
@ -6487,7 +6487,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ed.hasSlicing()) { if (ed.hasSlicing()) {
if (slicer != null && slicer.getPath().equals(ed.getPath())) { if (slicer != null && slicer.getPath().equals(ed.getPath())) {
String errorContext = "profile " + profile.getVersionedUrl(); String errorContext = "profile " + profile.getVersionedUrl();
if (resource.hasChild(ID) && !resource.getChildValue(ID).isEmpty()) { if (resource.hasChild(ID, false) && !resource.getChildValue(ID).isEmpty()) {
errorContext += "; instance " + resource.getChildValue("id"); errorContext += "; instance " + resource.getChildValue("id");
} }
throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext)); throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));
@ -6670,14 +6670,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ei.getDefinition().hasExtension(ToolingExtensions.EXT_ID_EXPECTATION)) { if (ei.getDefinition().hasExtension(ToolingExtensions.EXT_ID_EXPECTATION)) {
return IdStatus.fromCode(ToolingExtensions.readStringExtension(ei.getDefinition(),ToolingExtensions.EXT_ID_EXPECTATION)); return IdStatus.fromCode(ToolingExtensions.readStringExtension(ei.getDefinition(),ToolingExtensions.EXT_ID_EXPECTATION));
} else if (isBundleEntry(ei.getPath())) { } else if (isBundleEntry(ei.getPath())) {
Element req = ep.getNamedChild("request"); Element req = ep.getNamedChild("request", false);
Element resp = ep.getNamedChild("response"); Element resp = ep.getNamedChild("response", false);
Element fullUrl = ep.getNamedChild(FULL_URL); Element fullUrl = ep.getNamedChild(FULL_URL, false);
Element method = null; Element method = null;
Element url = null; Element url = null;
if (req != null) { if (req != null) {
method = req.getNamedChild("method"); method = req.getNamedChild("method", false);
url = req.getNamedChild("url"); url = req.getNamedChild("url", false);
} }
if (resp != null) { if (resp != null) {
return IdStatus.OPTIONAL; return IdStatus.OPTIONAL;
@ -6840,7 +6840,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean IsExemptInvariant(String path, Element element, ElementDefinitionConstraintComponent inv) { private boolean IsExemptInvariant(String path, Element element, ElementDefinitionConstraintComponent inv) {
if ("eld-24".equals(inv.getKey())) { if ("eld-24".equals(inv.getKey())) {
String p = element.getNamedChildValue("path"); String p = element.getNamedChildValue("path", false);
return (p != null) && ((p.endsWith("xtension.url") || p.endsWith(".id"))); return (p != null) && ((p.endsWith("xtension.url") || p.endsWith(".id")));
} }
return false; return false;
@ -6883,13 +6883,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// todo: validate everything in this bundle. // todo: validate everything in this bundle.
} }
if (rok) { if (rok) {
if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID) == null)) { if (idstatus == IdStatus.REQUIRED && (element.getNamedChild(ID, false) == null)) {
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_MISSING) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_MISSING) && ok;
} else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild(ID) != null)) { } else if (idstatus == IdStatus.PROHIBITED && (element.getNamedChild(ID, false) != null)) {
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_PROHIBITED) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.RESOURCE_RES_ID_PROHIBITED) && ok;
} }
if (element.getNamedChild(ID) != null) { if (element.getNamedChild(ID, false) != null) {
Element eid = element.getNamedChild(ID); Element eid = element.getNamedChild(ID, false);
if (eid.getProperty() != null && eid.getProperty().getDefinition() != null && eid.getProperty().getDefinition().getBase().getPath().equals("Resource.id")) { if (eid.getProperty() != null && eid.getProperty().getDefinition() != null && eid.getProperty().getDefinition().getBase().getPath().equals("Resource.id")) {
NodeStack ns = stack.push(eid, -1, eid.getProperty().getDefinition(), null); NodeStack ns = stack.push(eid, -1, eid.getProperty().getDefinition(), null);
if (eid.primitiveValue() != null && eid.primitiveValue().length() > 64) { if (eid.primitiveValue() != null && eid.primitiveValue().length() > 64) {
@ -6958,7 +6958,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
bundle.getElement().getNamedChildren(ENTRY, list); bundle.getElement().getNamedChildren(ENTRY, list);
if (list.isEmpty()) if (list.isEmpty())
return null; return null;
Element resource = list.get(0).getNamedChild(RESOURCE); Element resource = list.get(0).getNamedChild(RESOURCE, false);
if (resource == null) if (resource == null)
return null; return null;
else { else {

View File

@ -25,12 +25,40 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.validation.instance.InstanceValidator;
import org.hl7.fhir.validation.instance.PercentageTracker; import org.hl7.fhir.validation.instance.PercentageTracker;
import org.hl7.fhir.validation.instance.type.BundleValidator.StringWithSource;
import org.hl7.fhir.validation.instance.utils.EntrySummary; import org.hl7.fhir.validation.instance.utils.EntrySummary;
import org.hl7.fhir.validation.instance.utils.IndexedElement; import org.hl7.fhir.validation.instance.utils.IndexedElement;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
import org.hl7.fhir.validation.instance.utils.ValidationContext; import org.hl7.fhir.validation.instance.utils.ValidationContext;
public class BundleValidator extends BaseValidator { public class BundleValidator extends BaseValidator {
public class StringWithSource {
private String reference;
private Element source;
private boolean warning;
public StringWithSource(String reference, Element source, boolean warning) {
this.reference = reference;
this.source = source;
this.warning = warning;
}
public String getReference() {
return reference;
}
public Element getSource() {
return source;
}
public boolean isWarning() {
return warning;
}
}
public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?"; public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?";
private String serverBase; private String serverBase;
@ -41,7 +69,7 @@ public class BundleValidator extends BaseValidator {
public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) { public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) {
boolean ok = true; boolean ok = true;
String type = bundle.getNamedChildValue(TYPE); String type = bundle.getNamedChildValue(TYPE, false);
type = StringUtils.defaultString(type); type = StringUtils.defaultString(type);
List<Element> entries = new ArrayList<Element>(); List<Element> entries = new ArrayList<Element>();
bundle.getNamedChildren(ENTRY, entries); bundle.getNamedChildren(ENTRY, entries);
@ -63,12 +91,12 @@ public class BundleValidator extends BaseValidator {
// Get the stack of the first entry // Get the stack of the first entry
NodeStack firstStack = stack.push(firstEntry, 1, null, null); NodeStack firstStack = stack.push(firstEntry, 1, null, null);
String fullUrl = firstEntry.getNamedChildValue(FULL_URL); String fullUrl = firstEntry.getNamedChildValue(FULL_URL, false);
if (type.equals(DOCUMENT)) { if (type.equals(DOCUMENT)) {
Element resource = firstEntry.getNamedChild(RESOURCE); Element resource = firstEntry.getNamedChild(RESOURCE, false);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
String id = resource.getNamedChildValue(ID); String id = resource.getNamedChildValue(ID, false);
ok = validateDocument(errors, bundle, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok; ok = validateDocument(errors, bundle, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok;
} }
if (!VersionUtilities.isThisOrLater(FHIRVersion._4_0_1.getDisplay(), bundle.getProperty().getStructure().getFhirVersion().getDisplay())) { if (!VersionUtilities.isThisOrLater(FHIRVersion._4_0_1.getDisplay(), bundle.getProperty().getStructure().getFhirVersion().getDisplay())) {
@ -76,9 +104,9 @@ public class BundleValidator extends BaseValidator {
} }
ok = checkAllInterlinked(errors, entries, stack, bundle, false) && ok; ok = checkAllInterlinked(errors, entries, stack, bundle, false) && ok;
} else if (type.equals(MESSAGE)) { } else if (type.equals(MESSAGE)) {
Element resource = firstEntry.getNamedChild(RESOURCE); Element resource = firstEntry.getNamedChild(RESOURCE, false);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, firstEntry.line(), firstEntry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), resource != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFIRSTRESOURCE)) {
String id = resource.getNamedChildValue(ID); String id = resource.getNamedChildValue(ID, false);
ok = validateMessage(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok; ok = validateMessage(errors, entries, resource, firstStack.push(resource, -1, null, null), fullUrl, id) && ok;
ok = checkAllInterlinked(errors, entries, stack, bundle, true) && ok; ok = checkAllInterlinked(errors, entries, stack, bundle, true) && ok;
} }
@ -96,7 +124,7 @@ public class BundleValidator extends BaseValidator {
for (Element entry : entries) { for (Element entry : entries) {
NodeStack estack = stack.push(entry, count, null, null); NodeStack estack = stack.push(entry, count, null, null);
String fullUrl = entry.getNamedChildValue(FULL_URL); String fullUrl = entry.getNamedChildValue(FULL_URL, false);
String url = getCanonicalURLForEntry(entry); String url = getCanonicalURLForEntry(entry);
String id = getIdForEntry(entry); String id = getIdForEntry(entry);
String rtype = getTypeForEntry(entry); String rtype = getTypeForEntry(entry);
@ -118,7 +146,7 @@ public class BundleValidator extends BaseValidator {
if (url != null) { if (url != null) {
if (!(!url.equals(fullUrl) || (url.matches(urlRegex) && url.endsWith("/" + id))) && !isV3orV2Url(url)) if (!(!url.equals(fullUrl) || (url.matches(urlRegex) && url.endsWith("/" + id))) && !isV3orV2Url(url))
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_MISMATCHIDURL, url, fullUrl, id) && ok;
ok = rule(errors, NO_RULE_DATE, 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) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath(ENTRY, PATH_ARG), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild(RESOURCE, false).fhirType(), id))), I18nConstants.BUNDLE_BUNDLE_ENTRY_CANONICAL, url, fullUrl) && ok;
} }
if (!VersionUtilities.isR2Ver(context.getVersion())) { if (!VersionUtilities.isR2Ver(context.getVersion())) {
@ -128,7 +156,7 @@ public class BundleValidator extends BaseValidator {
if (rtype != null) { if (rtype != null) {
int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0; int rcount = counter.containsKey(rtype) ? counter.get(rtype)+1 : 0;
counter.put(rtype, rcount); counter.put(rtype, rcount);
Element res = entry.getNamedChild(RESOURCE); Element res = entry.getNamedChild(RESOURCE, false);
NodeStack rstack = estack.push(res, -1, null, null); NodeStack rstack = estack.push(res, -1, null, null);
for (BundleValidationRule bvr : validator().getBundleValidationRules()) { for (BundleValidationRule bvr : validator().getBundleValidationRules()) {
if (meetsRule(bvr, rtype, rcount, count)) { if (meetsRule(bvr, rtype, rcount, count)) {
@ -179,7 +207,7 @@ public class BundleValidator extends BaseValidator {
private boolean validateDocumentLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) { private boolean validateDocumentLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) {
boolean ok = true; boolean ok = true;
Element relE = link.getNamedChild("relation"); Element relE = link.getNamedChild("relation", false);
if (relE != null) { if (relE != null) {
NodeStack relStack = stack.push(relE, -1, null, null); NodeStack relStack = stack.push(relE, -1, null, null);
String rel = relE.getValue(); String rel = relE.getValue();
@ -188,7 +216,7 @@ public class BundleValidator extends BaseValidator {
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; 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)) { if ("stylesheet".equals(rel)) {
Element urlE = link.getNamedChild("url"); Element urlE = link.getNamedChild("url", false);
if (urlE != null) { if (urlE != null) {
NodeStack urlStack = stack.push(urlE, -1, null, null); NodeStack urlStack = stack.push(urlE, -1, null, null);
String url = urlE.getValue(); String url = urlE.getValue();
@ -210,7 +238,7 @@ public class BundleValidator extends BaseValidator {
// has to resolve in the bundle // has to resolve in the bundle
boolean found = false; boolean found = false;
for (Element e : entries) { for (Element e : entries) {
Element res = e.getNamedChild("resource"); Element res = e.getNamedChild(RESOURCE, false);
if (res != null && (""+res.fhirType()+"/"+res.getIdBase()).equals(url)) { if (res != null && (""+res.fhirType()+"/"+res.getIdBase()).equals(url)) {
found = true; found = true;
break; break;
@ -227,7 +255,7 @@ public class BundleValidator extends BaseValidator {
private boolean validateMessageLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) { private boolean validateMessageLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack, List<Element> entries) {
boolean ok = true; boolean ok = true;
Element relE = link.getNamedChild("relation"); Element relE = link.getNamedChild("relation", false);
if (relE != null) { if (relE != null) {
NodeStack relStack = stack.push(relE, -1, null, null); NodeStack relStack = stack.push(relE, -1, null, null);
String rel = relE.getValue(); String rel = relE.getValue();
@ -240,7 +268,7 @@ public class BundleValidator extends BaseValidator {
} }
private boolean validateSearchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) { private boolean validateSearchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
String rel = StringUtils.defaultString(link.getNamedChildValue("relation")); String rel = StringUtils.defaultString(link.getNamedChildValue("relation", false));
if (Utilities.existsInList(rel, "first", "previous", "next", "last", "self")) { 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); 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 { } else {
@ -250,7 +278,7 @@ public class BundleValidator extends BaseValidator {
private boolean relationshipUnique(String rel, Element link, List<Element> links) { private boolean relationshipUnique(String rel, Element link, List<Element> links) {
for (Element l : links) { for (Element l : links) {
if (l != link && rel.equals(l.getNamedChildValue("relation"))) { if (l != link && rel.equals(l.getNamedChildValue("relation", false))) {
return false; return false;
} }
if (l == link) { if (l == link) {
@ -263,7 +291,7 @@ public class BundleValidator extends BaseValidator {
private boolean validateCollectionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) { private boolean validateCollectionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
boolean ok = true; boolean ok = true;
Element relE = link.getNamedChild("relation"); Element relE = link.getNamedChild("relation", false);
if (relE != null) { if (relE != null) {
NodeStack relStack = stack.push(relE, -1, null, null); NodeStack relStack = stack.push(relE, -1, null, null);
String rel = relE.getValue(); String rel = relE.getValue();
@ -277,7 +305,7 @@ public class BundleValidator extends BaseValidator {
private boolean validateSubscriptionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) { private boolean validateSubscriptionLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
boolean ok = true; boolean ok = true;
Element relE = link.getNamedChild("relation"); Element relE = link.getNamedChild("relation", false);
if (relE != null) { if (relE != null) {
NodeStack relStack = stack.push(relE, -1, null, null); NodeStack relStack = stack.push(relE, -1, null, null);
String rel = relE.getValue(); String rel = relE.getValue();
@ -291,7 +319,7 @@ public class BundleValidator extends BaseValidator {
private boolean validateTransactionOrBatchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) { private boolean validateTransactionOrBatchLink(List<ValidationMessage> errors, Element bundle, List<Element> links, Element link, NodeStack stack) {
boolean ok = true; boolean ok = true;
Element relE = link.getNamedChild("relation"); Element relE = link.getNamedChild("relation", false);
if (relE != null) { if (relE != null) {
NodeStack relStack = stack.push(relE, -1, null, null); NodeStack relStack = stack.push(relE, -1, null, null);
String rel = relE.getValue(); String rel = relE.getValue();
@ -314,7 +342,7 @@ public class BundleValidator extends BaseValidator {
if (selfLink == null) { if (selfLink == null) {
warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_NOSELF); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_NOSELF);
} else { } else {
readSearchResourceTypes(selfLink.getNamedChildValue("url"), types); readSearchResourceTypes(selfLink.getNamedChildValue("url", false), types);
if (types.size() == 0) { if (types.size() == 0) {
hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_SELF_NOT_UNDERSTOOD); hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_SEARCH_SELF_NOT_UNDERSTOOD);
} }
@ -328,7 +356,7 @@ public class BundleValidator extends BaseValidator {
for (Element entry : entries) { for (Element entry : entries) {
NodeStack estack = stack.push(entry, count, null, null); NodeStack estack = stack.push(entry, count, null, null);
count++; count++;
Element res = entry.getNamedChild("resource"); Element res = entry.getNamedChild(RESOURCE, false);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) {
NodeStack rstack = estack.push(res, -1, null, null); NodeStack rstack = estack.push(res, -1, null, null);
String rt = res.fhirType(); String rt = res.fhirType();
@ -336,11 +364,11 @@ public class BundleValidator extends BaseValidator {
if (bok == null) { if (bok == null) {
typeProblem = true; typeProblem = true;
hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), selfLink == null, I18nConstants.BUNDLE_SEARCH_ENTRY_TYPE_NOT_SURE); hint(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), selfLink == null, I18nConstants.BUNDLE_SEARCH_ENTRY_TYPE_NOT_SURE);
String id = res.getNamedChildValue("id"); String id = res.getNamedChildValue("id", false);
warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null || "OperationOutcome".equals(rt), I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null || "OperationOutcome".equals(rt), I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID);
} else if (bok) { } else if (bok) {
if (!"OperationOutcome".equals(rt)) { if (!"OperationOutcome".equals(rt)) {
String id = res.getNamedChildValue("id"); String id = res.getNamedChildValue("id", false);
warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID);
if (rtype != null && !rt.equals(rtype)) { if (rtype != null && !rt.equals(rtype)) {
typeProblem = true; typeProblem = true;
@ -366,17 +394,17 @@ public class BundleValidator extends BaseValidator {
for (Element entry : entries) { for (Element entry : entries) {
NodeStack estack = stack.push(entry, count, null, null); NodeStack estack = stack.push(entry, count, null, null);
count++; count++;
Element res = entry.getNamedChild("resource"); Element res = entry.getNamedChild(RESOURCE, false);
String sm = null; String sm = null;
Element s = entry.getNamedChild("search"); Element s = entry.getNamedChild("search", false);
if (s != null) { if (s != null) {
sm = s.getNamedChildValue("mode"); sm = s.getNamedChildValue("mode", false);
} }
warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), sm != null, I18nConstants.BUNDLE_SEARCH_NO_MODE); warning(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), sm != null, I18nConstants.BUNDLE_SEARCH_NO_MODE);
if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) { if (rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), estack.getLiteralPath(), res != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE)) {
NodeStack rstack = estack.push(res, -1, null, null); NodeStack rstack = estack.push(res, -1, null, null);
String rt = res.fhirType(); String rt = res.fhirType();
String id = res.getNamedChildValue("id"); String id = res.getNamedChildValue("id", false);
if (sm != null) { if (sm != null) {
if ("match".equals(sm)) { if ("match".equals(sm)) {
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, bundle.line(), bundle.col(), rstack.getLiteralPath(), id != null, I18nConstants.BUNDLE_SEARCH_ENTRY_NO_RESOURCE_ID) && ok;
@ -408,9 +436,9 @@ public class BundleValidator extends BaseValidator {
boolean any = false; boolean any = false;
for (Element entry : entries) { for (Element entry : entries) {
String sm = null; String sm = null;
Element s = entry.getNamedChild("search"); Element s = entry.getNamedChild("search", false);
if (s != null) { if (s != null) {
sm = s.getNamedChildValue("mode"); sm = s.getNamedChildValue("mode", false);
} }
if (sm != null) { if (sm != null) {
any = true; any = true;
@ -456,7 +484,7 @@ public class BundleValidator extends BaseValidator {
private Element getSelfLink(List<Element> links) { private Element getSelfLink(List<Element> links) {
for (Element link : links) { for (Element link : links) {
if ("self".equals(link.getNamedChildValue("relation"))) { if ("self".equals(link.getNamedChildValue("relation", false))) {
return link; return link;
} }
} }
@ -524,20 +552,18 @@ public class BundleValidator extends BaseValidator {
public boolean validateDocumentReference(List<ValidationMessage> errors, Element bundle, List<Element> entries, Element composition, NodeStack stack, String fullUrl, String id, boolean repeats, String propName, String title) { public boolean validateDocumentReference(List<ValidationMessage> errors, Element bundle, List<Element> entries, Element composition, NodeStack stack, String fullUrl, String id, boolean repeats, String propName, String title) {
boolean ok = true; boolean ok = true;
List<Element> list = new ArrayList<>();
composition.getNamedChildren(propName, list);
if (repeats) { if (repeats) {
List<Element> list = new ArrayList<>();
composition.getNamedChildren(propName, list);
int i = 1; int i = 1;
for (Element elem : list) { for (Element elem : list) {
ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, i, null, null), fullUrl, "Composition", id) && ok; ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, i, null, null), fullUrl, "Composition", id) && ok;
i++; i++;
} }
} else if (list.size() > 0) {
} else { Element elem = list.get(0);
Element elem = composition.getNamedChild(propName); ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, -1, null, null), fullUrl, "Composition", id) && ok;
if (elem != null) {
ok = validateBundleReference(errors, bundle, entries, elem, title + "." + propName, stack.push(elem, -1, null, null), fullUrl, "Composition", id) && ok;
}
} }
return ok; return ok;
} }
@ -556,16 +582,14 @@ public class BundleValidator extends BaseValidator {
private boolean validateBundleReference(List<ValidationMessage> errors, Element bundle, List<Element> entries, Element ref, String name, NodeStack stack, String fullUrl, String type, String id) { private boolean validateBundleReference(List<ValidationMessage> errors, Element bundle, List<Element> entries, Element ref, String name, NodeStack stack, String fullUrl, String type, String id) {
String reference = null; String reference = null;
try { try {
reference = ref.getNamedChildValue("reference"); reference = ref.getNamedChildValue("reference", false);
} catch (Error e) { } catch (Error e) {
} }
if (ref != null && !Utilities.noString(reference) && !reference.startsWith("#")) { if (ref != null && !Utilities.noString(reference) && !reference.startsWith("#")) {
ElementMatch target = resolveInBundle(bundle, entries, reference, fullUrl, type, id); Element target = resolveInBundle(bundle, entries, reference, fullUrl, type, id, stack, errors, name, ref, false);
if (target == null) { if (target == null) {
return rule(errors, NO_RULE_DATE, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, reference, name); return false;
} else {
return rule(errors, NO_RULE_DATE, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target.isValid(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, reference, name);
} }
} }
return true; return true;
@ -586,9 +610,9 @@ public class BundleValidator extends BaseValidator {
* @param stack {@link NodeStack} * @param stack {@link NodeStack}
*/ */
private boolean handleSpecialCaseForLastUpdated(Element bundle, List<ValidationMessage> errors, NodeStack stack) { private boolean handleSpecialCaseForLastUpdated(Element bundle, List<ValidationMessage> errors, NodeStack stack) {
boolean ok = bundle.hasChild(META) boolean ok = bundle.hasChild(META, false)
&& bundle.getNamedChild(META).hasChild(LAST_UPDATED) && bundle.getNamedChild(META, false).hasChild(LAST_UPDATED, false)
&& bundle.getNamedChild(META).getNamedChild(LAST_UPDATED).hasValue(); && bundle.getNamedChild(META, false).getNamedChild(LAST_UPDATED, false).hasValue();
ruleHtml(errors, NO_RULE_DATE, IssueType.REQUIRED, stack.getLiteralPath(), ok, I18nConstants.DOCUMENT_DATE_REQUIRED, I18nConstants.DOCUMENT_DATE_REQUIRED_HTML); ruleHtml(errors, NO_RULE_DATE, IssueType.REQUIRED, stack.getLiteralPath(), ok, I18nConstants.DOCUMENT_DATE_REQUIRED, I18nConstants.DOCUMENT_DATE_REQUIRED_HTML);
return ok; return ok;
} }
@ -598,30 +622,27 @@ public class BundleValidator extends BaseValidator {
List<EntrySummary> entryList = new ArrayList<>(); List<EntrySummary> entryList = new ArrayList<>();
int i = 0; int i = 0;
for (Element entry : entries) { for (Element entry : entries) {
Element r = entry.getNamedChild(RESOURCE); Element r = entry.getNamedChild(RESOURCE, false);
if (r != null) { if (r != null) {
EntrySummary e = new EntrySummary(i, entry, r); EntrySummary e = new EntrySummary(i, entry, r);
entryList.add(e); entryList.add(e);
// System.out.println("Found entry "+e.dbg());
} }
i++; i++;
} }
for (EntrySummary e : entryList) { for (EntrySummary e : entryList) {
Set<String> references = findReferences(e.getEntry()); List<StringWithSource> references = findReferences(e.getEntry());
for (String ref : references) { for (StringWithSource ref : references) {
ElementMatch tgt = resolveInBundle(bundle, entries, ref, e.getEntry().getChildValue(FULL_URL), e.getResource().fhirType(), e.getResource().getIdBase()); Element tgt = resolveInBundle(bundle, entries, ref.getReference(), e.getEntry().getChildValue(FULL_URL), e.getResource().fhirType(), e.getResource().getIdBase(), stack, errors, ref.getSource().getPath(), ref.getSource(), ref.isWarning());
if (tgt != null && tgt.isValid()) { if (tgt != null) {
EntrySummary t = entryForTarget(entryList, tgt.getElement()); EntrySummary t = entryForTarget(entryList, tgt);
if (t != null ) { if (t != null ) {
if (t != e) { if (t != e) {
// System.out.println("Entry "+e.getIndex()+" refers to "+t.getIndex()+" by ref '"+ref+"'"); e.getTargets().add(t);
e.getTargets().add(t); } else {
} else { }
// System.out.println("Entry "+e.getIndex()+" refers to itself by '"+ref+"'"); }
} }
}
}
} }
} }
@ -684,8 +705,8 @@ public class BundleValidator extends BaseValidator {
private void visitBundleLinks(Set<EntrySummary> visited, List<EntrySummary> entryList, Element bundle) { private void visitBundleLinks(Set<EntrySummary> visited, List<EntrySummary> entryList, Element bundle) {
List<Element> links = bundle.getChildrenByName("link"); List<Element> links = bundle.getChildrenByName("link");
for (Element link : links) { for (Element link : links) {
String rel = link.getNamedChildValue("relation"); String rel = link.getNamedChildValue("relation", false);
String url = link.getNamedChildValue("url"); String url = link.getNamedChildValue("url", false);
if (rel != null && url != null) { if (rel != null && url != null) {
if (Utilities.existsInList(rel, "stylesheet")) { if (Utilities.existsInList(rel, "stylesheet")) {
for (EntrySummary e : entryList) { for (EntrySummary e : entryList) {
@ -706,21 +727,21 @@ public class BundleValidator extends BaseValidator {
} }
private String getCanonicalURLForEntry(Element entry) { private String getCanonicalURLForEntry(Element entry) {
Element e = entry.getNamedChild(RESOURCE); Element e = entry.getNamedChild(RESOURCE, false);
if (e == null) if (e == null)
return null; return null;
return e.getNamedChildValue("url"); return e.getNamedChildValue("url", false);
} }
private String getIdForEntry(Element entry) { private String getIdForEntry(Element entry) {
Element e = entry.getNamedChild(RESOURCE); Element e = entry.getNamedChild(RESOURCE, false);
if (e == null) if (e == null)
return null; return null;
return e.getNamedChildValue(ID); return e.getNamedChildValue(ID, false);
} }
private String getTypeForEntry(Element entry) { private String getTypeForEntry(Element entry) {
Element e = entry.getNamedChild(RESOURCE); Element e = entry.getNamedChild(RESOURCE, false);
if (e == null) if (e == null)
return null; return null;
return e.fhirType(); return e.fhirType();
@ -739,9 +760,9 @@ public class BundleValidator extends BaseValidator {
// TODO: Need to handle _version // TODO: Need to handle _version
int i = 1; int i = 1;
for (Element entry : entries) { for (Element entry : entries) {
String fullUrl = entry.getNamedChildValue(FULL_URL); String fullUrl = entry.getNamedChildValue(FULL_URL, false);
Element resource = entry.getNamedChild(RESOURCE); Element resource = entry.getNamedChild(RESOURCE, false);
String id = resource != null ? resource.getNamedChildValue(ID) : null; String id = resource != null ? resource.getNamedChildValue(ID, false) : null;
if (id != null && fullUrl != null) { if (id != null && fullUrl != null) {
String urlId = null; String urlId = null;
if (fullUrl.startsWith("https://") || fullUrl.startsWith("http://")) { if (fullUrl.startsWith("https://") || fullUrl.startsWith("http://")) {
@ -780,7 +801,7 @@ public class BundleValidator extends BaseValidator {
// //
// private boolean followResourceLinks(Element entry, Map<String, Element> visitedResources, Map<Element, Element> candidateEntries, List<Element> candidateResources, List<ValidationMessage> errors, NodeStack stack, int depth) { // private boolean followResourceLinks(Element entry, Map<String, Element> visitedResources, Map<Element, Element> candidateEntries, List<Element> candidateResources, List<ValidationMessage> errors, NodeStack stack, int depth) {
// boolean ok = true; // boolean ok = true;
// Element resource = entry.getNamedChild(RESOURCE); // Element resource = entry.getNamedChild(RESOURCE, false);
// if (visitedResources.containsValue(resource)) // if (visitedResources.containsValue(resource))
// return ok; // return ok;
// //
@ -801,29 +822,40 @@ public class BundleValidator extends BaseValidator {
// } // }
private Set<String> findReferences(Element start) { private List<StringWithSource> findReferences(Element start) {
Set<String> references = new HashSet<String>(); List<StringWithSource> references = new ArrayList<StringWithSource>();
findReferences(start, references); findReferences(start, references);
return references; return references;
} }
private void findReferences(Element start, Set<String> references) { private void findReferences(Element start, List<StringWithSource> references) {
for (Element child : start.getChildren()) { for (Element child : start.getChildren()) {
if (child.getType().equals("Reference")) { if (child.getType().equals("Reference")) {
String ref = child.getChildValue("reference"); String ref = child.getChildValue("reference");
if (ref != null && !ref.startsWith("#")) if (ref != null && !ref.startsWith("#") && !hasReference(ref, references))
references.add(ref); references.add(new StringWithSource(ref, child, false));
} }
if (child.getType().equals("url") || child.getType().equals("uri") || child.getType().equals("canonical")) { if (Utilities.existsInList(child.getType(), "url", "uri"/*, "canonical"*/) &&
!Utilities.existsInList(child.getName(), "system") &&
!Utilities.existsInList(child.getProperty().getDefinition().getPath(), "Bundle.entry.fullUrl", "Coding.system", "Identifier.system", "Meta.profile", "Extension.url", "Quantity.system",
"MessageHeader.source.endpoint", "MessageHeader.destination.endpoint", "Endpoint.address")) {
String ref = child.primitiveValue(); String ref = child.primitiveValue();
if (ref != null && !ref.startsWith("#")) if (ref != null && !ref.startsWith("#") && !hasReference(ref, references))
references.add(ref); references.add(new StringWithSource(ref, child, true));
} }
findReferences(child, references); findReferences(child, references);
} }
} }
private boolean hasReference(String ref, List<StringWithSource> references) {
for (StringWithSource t : references) {
if (ref.equals(t.getReference())) {
return true;
}
}
return false;
}
// hack for pre-UTG v2/v3 // hack for pre-UTG v2/v3
private boolean isV3orV2Url(String url) { private boolean isV3orV2Url(String url) {

View File

@ -29,16 +29,16 @@ public class CodeSystemValidator extends BaseValidator {
public boolean validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) { public boolean validateCodeSystem(List<ValidationMessage> errors, Element cs, NodeStack stack, ValidationOptions options) {
boolean ok = true; boolean ok = true;
String url = cs.getNamedChildValue("url"); String url = cs.getNamedChildValue("url", false);
String content = cs.getNamedChildValue("content"); String content = cs.getNamedChildValue("content", false);
String caseSensitive = cs.getNamedChildValue("caseSensitive"); String caseSensitive = cs.getNamedChildValue("caseSensitive", false);
String hierarchyMeaning = cs.getNamedChildValue("hierarchyMeaning"); String hierarchyMeaning = cs.getNamedChildValue("hierarchyMeaning", false);
String supp = cs.getNamedChildValue("supplements"); String supp = cs.getNamedChildValue("supplements", false);
int count = countConcepts(cs); int count = countConcepts(cs);
metaChecks(errors, cs, stack, url, content, caseSensitive, hierarchyMeaning, !Utilities.noString(supp), count, supp); metaChecks(errors, cs, stack, url, content, caseSensitive, hierarchyMeaning, !Utilities.noString(supp), count, supp);
String vsu = cs.getNamedChildValue("valueSet"); String vsu = cs.getNamedChildValue("valueSet", false);
if (!Utilities.noString(vsu)) { if (!Utilities.noString(vsu)) {
hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE); hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), "complete".equals(content), I18nConstants.CODESYSTEM_CS_NO_VS_NOTCOMPLETE);
ValueSet vs; ValueSet vs;
@ -98,29 +98,29 @@ public class CodeSystemValidator extends BaseValidator {
if (parent.isForPublication()) { if (parent.isForPublication()) {
if (isHL7(cs)) { if (isHL7(cs)) {
boolean ok = true; boolean ok = true;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "url") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "url") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "version") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "version") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "title") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "title") && ok;
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7, "name");
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "status") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "status") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "experimental") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "experimental") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "description") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "description") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "content") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "content") && ok;
if (!"supplement".equals(cs.getChildValue("content"))) { if (!"supplement".equals(cs.getChildValue("content"))) {
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "caseSensitive") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING_HL7, "caseSensitive") && ok;
} }
return ok; return ok;
} else { } else {
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "url"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "url");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "version"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "version");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "title"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "title");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CODESYSTEM_SHAREABLE_EXTRA_MISSING, "name");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "status"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "status");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "experimental"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "experimental");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "description"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "description");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "content"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("content", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "content");
if (!"supplement".equals(cs.getChildValue("content"))) { if (!"supplement".equals(cs.getChildValue("content"))) {
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive"), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "caseSensitive"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("caseSensitive", false), I18nConstants.CODESYSTEM_SHAREABLE_MISSING, "caseSensitive");
} }
} }
} }
@ -130,15 +130,15 @@ public class CodeSystemValidator extends BaseValidator {
private void metaChecks(List<ValidationMessage> errors, Element cs, NodeStack stack, String url, String content, String caseSensitive, String hierarchyMeaning, boolean isSupplement, int count, String supp) { private void metaChecks(List<ValidationMessage> errors, Element cs, NodeStack stack, String url, String content, String caseSensitive, String hierarchyMeaning, boolean isSupplement, int count, String supp) {
if (isSupplement) { if (isSupplement) {
if (!"supplement".equals(content)) { if (!"supplement".equals(content)) {
NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); NodeStack s = stack.push(cs.getNamedChild("content", false), -1, null, null);
rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_WRONG);
} }
if (!Utilities.noString(caseSensitive)) { if (!Utilities.noString(caseSensitive)) {
NodeStack s = stack.push(cs.getNamedChild("caseSensitive"), -1, null, null); NodeStack s = stack.push(cs.getNamedChild("caseSensitive", false), -1, null, null);
rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive"); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "caseSensitive");
} }
if (!Utilities.noString(hierarchyMeaning)) { if (!Utilities.noString(hierarchyMeaning)) {
NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning"), -1, null, null); NodeStack s = stack.push(cs.getNamedChild("hierarchyMeaning", false), -1, null, null);
rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "hierarchyMeaning"); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL, "hierarchyMeaning");
} }
@ -146,7 +146,7 @@ public class CodeSystemValidator extends BaseValidator {
boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org")); boolean isHL7 = url != null && (url.contains("hl7.org") || url.contains("fhir.org"));
if (Utilities.noString(content)) { if (Utilities.noString(content)) {
NodeStack s = stack; NodeStack s = stack;
Element c = cs.getNamedChild("content"); Element c = cs.getNamedChild("content", false);
if (c != null) { if (c != null) {
s = stack.push(c, -1, null, null); s = stack.push(c, -1, null, null);
} }
@ -156,12 +156,12 @@ public class CodeSystemValidator extends BaseValidator {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "content"); warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_NONHL7_MISSING_ELEMENT, "content");
} }
} else if ("supplement".equals(content)) { } else if ("supplement".equals(content)) {
NodeStack s = stack.push(cs.getNamedChild("content"), -1, null, null); NodeStack s = stack.push(cs.getNamedChild("content", false), -1, null, null);
rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING); rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, s.getLiteralPath(), false, I18nConstants.CODESYSTEM_CS_HL7_PRESENT_ELEMENT_SUPPL_MISSING);
} }
if (Utilities.noString(caseSensitive)) { if (Utilities.noString(caseSensitive)) {
NodeStack s = stack; NodeStack s = stack;
Element c = cs.getNamedChild("caseSensitive"); Element c = cs.getNamedChild("caseSensitive", false);
if (c != null) { if (c != null) {
s = stack.push(c, -1, null, null); s = stack.push(c, -1, null, null);
} }
@ -173,7 +173,7 @@ public class CodeSystemValidator extends BaseValidator {
} }
if (Utilities.noString(hierarchyMeaning) && hasHeirarchy(cs)) { if (Utilities.noString(hierarchyMeaning) && hasHeirarchy(cs)) {
NodeStack s = stack; NodeStack s = stack;
Element c = cs.getNamedChild("hierarchyMeaning"); Element c = cs.getNamedChild("hierarchyMeaning", false);
if (c != null) { if (c != null) {
s = stack.push(c, -1, null, null); s = stack.push(c, -1, null, null);
} }
@ -185,10 +185,10 @@ public class CodeSystemValidator extends BaseValidator {
} }
} }
if (cs.hasChild("count")) { if (cs.hasChild("count", false)) {
int statedCount = Utilities.parseInt(cs.getNamedChildValue("count"), -1); int statedCount = Utilities.parseInt(cs.getNamedChildValue("count", false), -1);
if (statedCount > -1 && content != null) { // error elsewhere if (statedCount > -1 && content != null) { // error elsewhere
var nstack = stack.push(cs.getNamedChild("count"), -1, null, null); var nstack = stack.push(cs.getNamedChild("count", false), -1, null, null);
switch (content) { switch (content) {
case "complete": case "complete":
rule(errors, "2023-08-15", IssueType.INVALID, nstack, count == statedCount, I18nConstants.CODESYSTEM_CS_COUNT_COMPLETE_WRONG, count, statedCount); rule(errors, "2023-08-15", IssueType.INVALID, nstack, count == statedCount, I18nConstants.CODESYSTEM_CS_COUNT_COMPLETE_WRONG, count, statedCount);
@ -199,7 +199,7 @@ public class CodeSystemValidator extends BaseValidator {
break; break;
case "not-present": case "not-present":
if (cs.hasChildren("concept")) { if (cs.hasChildren("concept")) {
hint(errors, "2023-08-15", IssueType.INVALID, stack.push(cs.getNamedChild("concept"), -1, null, null), statedCount > 0, I18nConstants.CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO, statedCount); hint(errors, "2023-08-15", IssueType.INVALID, stack.push(cs.getNamedChild("concept", false), -1, null, null), statedCount > 0, I18nConstants.CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO, statedCount);
} }
break; break;
case "supplement": case "supplement":

View File

@ -187,13 +187,13 @@ public class ConceptMapValidator extends BaseValidator {
private VSReference readVSReference(Element cm, String... names) { private VSReference readVSReference(Element cm, String... names) {
for (String n : names) { for (String n : names) {
if (cm.hasChild(n)) { if (cm.hasChild(n, false)) {
Element e = cm.getNamedChild(n); Element e = cm.getNamedChild(n, false);
String ref = null; String ref = null;
if (e.isPrimitive()) { if (e.isPrimitive()) {
ref = e.primitiveValue(); ref = e.primitiveValue();
} else if (e.hasChild("reference")) { } else if (e.hasChild("reference", false)) {
ref = e.getNamedChildValue("reference"); ref = e.getNamedChildValue("reference", false);
} }
if (ref != null) { if (ref != null) {
VSReference res = new VSReference(); VSReference res = new VSReference();
@ -218,9 +218,9 @@ public class ConceptMapValidator extends BaseValidator {
ctxt.sourceScope = sourceScope; ctxt.sourceScope = sourceScope;
ctxt.targetScope = targetScope; ctxt.targetScope = targetScope;
Element e = grp.getNamedChild("source"); Element e = grp.getNamedChild("source", false);
if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_MISSING)) { if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_MISSING)) {
ctxt.source = readCSReference(e, grp.getNamedChild("sourceVersion")); ctxt.source = readCSReference(e, grp.getNamedChild("sourceVersion", false));
if (ctxt.source.cs != null) { if (ctxt.source.cs != null) {
if (ctxt.source.cs.getContent() == CodeSystemContentMode.NOTPRESENT) { if (ctxt.source.cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
ctxt.source.cs = null; ctxt.source.cs = null;
@ -231,9 +231,9 @@ public class ConceptMapValidator extends BaseValidator {
warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), sourceScope != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_UNKNOWN, e.getValue()); warning(errors, "2023-03-05", IssueType.NOTFOUND, grp.line(), grp.col(), stack.push(e, -1, null, null).getLiteralPath(), sourceScope != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_UNKNOWN, e.getValue());
} }
} }
e = grp.getNamedChild("target"); e = grp.getNamedChild("target", false);
if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_MISSING)) { if (warning(errors, "2023-03-05", IssueType.REQUIRED, grp.line(), grp.col(), stack.getLiteralPath(), e != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_MISSING)) {
ctxt.target = readCSReference(e, grp.getNamedChild("targetVersion")); ctxt.target = readCSReference(e, grp.getNamedChild("targetVersion", false));
if (ctxt.target.cs != null) { if (ctxt.target.cs != null) {
if (ctxt.target.cs.getContent() == CodeSystemContentMode.NOTPRESENT) { if (ctxt.target.cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
ctxt.target.cs = null; ctxt.target.cs = null;
@ -274,14 +274,14 @@ public class ConceptMapValidator extends BaseValidator {
private boolean validateGroupElement(List<ValidationMessage> errors, Element src, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, GroupContext ctxt) { private boolean validateGroupElement(List<ValidationMessage> errors, Element src, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, GroupContext ctxt) {
boolean ok = true; boolean ok = true;
Element code = src.getNamedChild("code"); Element code = src.getNamedChild("code", false);
if (code != null) { if (code != null) {
NodeStack cstack = stack.push(code, -1, null, null); NodeStack cstack = stack.push(code, -1, null, null);
if (ctxt.hasSourceCS()) { if (ctxt.hasSourceCS()) {
String c = code.getValue(); String c = code.getValue();
ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.source.cs, c); ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.source.cs, c);
if (warningOrError(ctxt.source.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_CODE_INVALID, c, ctxt.source.cs.getVersionedUrl())) { if (warningOrError(ctxt.source.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_SOURCE_CODE_INVALID, c, ctxt.source.cs.getVersionedUrl())) {
Element display = src.getNamedChild("display"); Element display = src.getNamedChild("display", false);
if (display != null) { if (display != null) {
warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.source.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_SOURCE_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.source.cs, cd)); warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.source.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_SOURCE_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.source.cs, cd));
} }
@ -311,14 +311,14 @@ public class ConceptMapValidator extends BaseValidator {
private boolean validateGroupElementTarget(List<ValidationMessage> errors, Element tgt, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, GroupContext ctxt) { private boolean validateGroupElementTarget(List<ValidationMessage> errors, Element tgt, NodeStack stack, Map<String, PropertyDefinition> props, Map<String, String> attribs, ValidationOptions options, GroupContext ctxt) {
boolean ok = true; boolean ok = true;
Element code = tgt.getNamedChild("code"); Element code = tgt.getNamedChild("code", false);
if (code != null) { if (code != null) {
NodeStack cstack = stack.push(code, -1, null, null); NodeStack cstack = stack.push(code, -1, null, null);
if (ctxt.hasTargetCS()) { if (ctxt.hasTargetCS()) {
String c = code.getValue(); String c = code.getValue();
ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.target.cs, c); ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(ctxt.target.cs, c);
if (warningOrError(ctxt.target.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_CODE_INVALID, c, ctxt.target.cs.getVersionedUrl())) { if (warningOrError(ctxt.target.cs.getContent() == CodeSystemContentMode.COMPLETE, errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), cd != null, I18nConstants.CONCEPTMAP_GROUP_TARGET_CODE_INVALID, c, ctxt.target.cs.getVersionedUrl())) {
Element display = tgt.getNamedChild("display"); Element display = tgt.getNamedChild("display", false);
if (display != null) { if (display != null) {
warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.target.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_TARGET_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.target.cs, cd)); warning(errors, "2023-03-05", IssueType.REQUIRED, code.line(), code.col(), cstack.getLiteralPath(), CodeSystemUtilities.checkDisplay(ctxt.target.cs, cd, display.getValue()), I18nConstants.CONCEPTMAP_GROUP_TARGET_DISPLAY_INVALID, display.getValue(), CodeSystemUtilities.getDisplays(ctxt.target.cs, cd));
} }
@ -362,8 +362,8 @@ public class ConceptMapValidator extends BaseValidator {
private boolean validateGroupElementTargetProperty(List<ValidationMessage> errors, Element property, NodeStack stack, Map<String, PropertyDefinition> props) { private boolean validateGroupElementTargetProperty(List<ValidationMessage> errors, Element property, NodeStack stack, Map<String, PropertyDefinition> props) {
boolean ok = true; boolean ok = true;
Element codeE = property.getNamedChild("code"); Element codeE = property.getNamedChild("code", false);
Element valueE = property.getNamedChild("value"); Element valueE = property.getNamedChild("value", false);
String code = codeE.getValue(); String code = codeE.getValue();
if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), props.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, props.keySet())) { if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), props.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, props.keySet())) {
PropertyDefinition defn = props.get(code); PropertyDefinition defn = props.get(code);
@ -388,8 +388,8 @@ public class ConceptMapValidator extends BaseValidator {
private boolean validateGroupElementTargetAttribute(List<ValidationMessage> errors, Element attribute, NodeStack stack, Map<String, String> attribs) { private boolean validateGroupElementTargetAttribute(List<ValidationMessage> errors, Element attribute, NodeStack stack, Map<String, String> attribs) {
boolean ok = true; boolean ok = true;
Element codeE = attribute.getNamedChild("attribute"); Element codeE = attribute.getNamedChild("attribute", false);
Element valueE = attribute.getNamedChild("value"); Element valueE = attribute.getNamedChild("value", false);
String code = codeE.getValue(); String code = codeE.getValue();
if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), attribs.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, attribs.keySet())) { if (rule(errors, "2023-03-05", IssueType.REQUIRED, codeE.line(), codeE.col(), stack.push(codeE, -1, null, null).getLiteralPath(), attribs.containsKey(code), I18nConstants.CONCEPTMAP_GROUP_TARGET_PROPERTY_INVALID, code, attribs.keySet())) {
NodeStack stackV = stack.push(valueE, -1, null, null); NodeStack stackV = stack.push(valueE, -1, null, null);
@ -404,22 +404,22 @@ public class ConceptMapValidator extends BaseValidator {
if (parent.isForPublication()) { if (parent.isForPublication()) {
if (isHL7(cs)) { if (isHL7(cs)) {
boolean ok = true; boolean ok = true;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "url") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "url") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "version") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "version") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "title") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "title") && ok;
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7, "name");
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "status") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "status") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "experimental") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "experimental") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "description") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING_HL7, "description") && ok;
return ok; return ok;
} else { } else {
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "url"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "url");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "version"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "version");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "title"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "title");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.CONCEPTMAP_SHAREABLE_EXTRA_MISSING, "name");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "status"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "status");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "experimental"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "experimental");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "description"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.CONCEPTMAP_SHAREABLE_MISSING, "description");
} }
} }
return true; return true;

View File

@ -62,22 +62,22 @@ public class MeasureValidator extends BaseValidator {
int c = 0; int c = 0;
for (Element group : groups) { for (Element group : groups) {
NodeStack ns = stack.push(group, c, null, null); NodeStack ns = stack.push(group, c, null, null);
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), groups.size() ==1 || group.hasChild("code"), I18nConstants.MEASURE_M_GROUP_CODE); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), groups.size() ==1 || group.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_CODE);
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), group.hasChildren("population"), I18nConstants.MEASURE_M_GROUP_POP); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, group.line(), group.col(), ns.getLiteralPath(), group.hasChildren("population"), I18nConstants.MEASURE_M_GROUP_POP);
int c1 = 0; int c1 = 0;
List<Element> pl = group.getChildrenByName("population"); List<Element> pl = group.getChildrenByName("population");
for (Element p : pl) { for (Element p : pl) {
NodeStack ns2 = ns.push(p, c1, null, null); NodeStack ns2 = ns.push(p, c1, null, null);
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, p.line(), p.col(), ns2.getLiteralPath(), pl.size() == 1 || p.hasChild("code"), I18nConstants.MEASURE_M_GROUP_POP_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, p.line(), p.col(), ns2.getLiteralPath(), pl.size() == 1 || p.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_POP_NO_CODE);
c1++; c1++;
} }
c1 = 0; c1 = 0;
List<Element> stl = group.getChildrenByName("stratifier"); List<Element> stl = group.getChildrenByName("stratifier");
for (Element st : stl) { for (Element st : stl) {
NodeStack ns2 = ns.push(st, c1, null, null); NodeStack ns2 = ns.push(st, c1, null, null);
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, st.line(), st.col(), ns2.getLiteralPath(), stl.size() == 1 || st.hasChild("code"), I18nConstants.MEASURE_M_GROUP_STRATA_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, st.line(), st.col(), ns2.getLiteralPath(), stl.size() == 1 || st.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_STRATA_NO_CODE);
if (st.hasChild("criteria")) { if (st.hasChild("criteria", false)) {
Element crit = st.getNamedChild("criteria"); Element crit = st.getNamedChild("criteria", false);
NodeStack nsc = ns2.push(crit, -1, null, null); NodeStack nsc = ns2.push(crit, -1, null, null);
ok = validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok; ok = validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok;
} }
@ -85,9 +85,9 @@ public class MeasureValidator extends BaseValidator {
List<Element> cpl = group.getChildrenByName("component"); List<Element> cpl = group.getChildrenByName("component");
for (Element cp : cpl) { for (Element cp : cpl) {
NodeStack ns3 = ns2.push(cp, c2, null, null); NodeStack ns3 = ns2.push(cp, c2, null, null);
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cp.line(), cp.col(), ns3.getLiteralPath(), cpl.size() == 1 || cp.hasChild("code"), I18nConstants.MEASURE_M_GROUP_STRATA_COMP_NO_CODE); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cp.line(), cp.col(), ns3.getLiteralPath(), cpl.size() == 1 || cp.hasChild("code", false), I18nConstants.MEASURE_M_GROUP_STRATA_COMP_NO_CODE);
if (cp.hasChild("criteria")) { if (cp.hasChild("criteria", false)) {
Element crit = cp.getNamedChild("criteria"); Element crit = cp.getNamedChild("criteria", false);
NodeStack nsc = ns3.push(crit, -1, null, null); NodeStack nsc = ns3.push(crit, -1, null, null);
ok= validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok; ok= validateMeasureCriteria(hostContext, errors, mctxt, crit, nsc) && ok;
} }
@ -109,23 +109,23 @@ public class MeasureValidator extends BaseValidator {
boolean ok = true; boolean ok = true;
if (parent.isForPublication()) { if (parent.isForPublication()) {
if (isHL7(cs)) { if (isHL7(cs)) {
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "url") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "url") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "version") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "version") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING_HL7, "name") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING_HL7, "name") && ok;
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "title"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "title");
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "status") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "status") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "experimental") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "experimental") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "publisher") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "publisher") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "description") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.MEASURE_SHAREABLE_MISSING_HL7, "description") && ok;
} else { } else {
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url"), I18nConstants.MEASURE_SHAREABLE_MISSING, "url"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("url", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "url");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version"), I18nConstants.MEASURE_SHAREABLE_MISSING, "version"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("version", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "version");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name"), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("name", false), I18nConstants.MEASURE_SHAREABLE_EXTRA_MISSING, "name");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title"), I18nConstants.MEASURE_SHAREABLE_MISSING, "title"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("title", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "title");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status"), I18nConstants.MEASURE_SHAREABLE_MISSING, "status"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("status", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "status");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental"), I18nConstants.MEASURE_SHAREABLE_MISSING, "experimental"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("experimental", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "experimental");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description"), I18nConstants.MEASURE_SHAREABLE_MISSING, "description"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("description", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "description");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher"), I18nConstants.MEASURE_SHAREABLE_MISSING, "publisher"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, cs.line(), cs.col(), stack.getLiteralPath(), cs.hasChild("publisher", false), I18nConstants.MEASURE_SHAREABLE_MISSING, "publisher");
} }
} }
return ok; return ok;
@ -208,7 +208,7 @@ public class MeasureValidator extends BaseValidator {
public boolean validateMeasureReport(ValidationContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException { public boolean validateMeasureReport(ValidationContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException {
boolean ok = true; boolean ok = true;
Element m = element.getNamedChild("measure"); Element m = element.getNamedChild("measure", false);
String measure = null; String measure = null;
if (m != null) { if (m != null) {
/* /*
@ -228,7 +228,7 @@ public class MeasureValidator extends BaseValidator {
Measure msrc = measure.startsWith("#") ? loadMeasure(element, measure.substring(1)) : context.fetchResource(Measure.class, measure); Measure msrc = measure.startsWith("#") ? loadMeasure(element, measure.substring(1)) : context.fetchResource(Measure.class, measure);
timeTracker.sd(t); timeTracker.sd(t);
if (warning(errors, NO_RULE_DATE, IssueType.REQUIRED, m.line(), m.col(), stack.getLiteralPath(), msrc != null, I18nConstants.MEASURE_MR_M_NOTFOUND, measure)) { if (warning(errors, NO_RULE_DATE, IssueType.REQUIRED, m.line(), m.col(), stack.getLiteralPath(), msrc != null, I18nConstants.MEASURE_MR_M_NOTFOUND, measure)) {
boolean inComplete = !"complete".equals(element.getNamedChildValue("status")); boolean inComplete = !"complete".equals(element.getNamedChildValue("status", false));
MeasureContext mc = new MeasureContext(msrc, element); MeasureContext mc = new MeasureContext(msrc, element);
NodeStack ns = stack.push(m, -1, m.getProperty().getDefinition(), m.getProperty().getDefinition()); NodeStack ns = stack.push(m, -1, m.getProperty().getDefinition(), m.getProperty().getDefinition());
hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, m.line(), m.col(), ns.getLiteralPath(), Utilities.existsInList(mc.scoring(), "proportion", "ratio", "continuous-variable", "cohort"), I18nConstants.MEASURE_MR_M_SCORING_UNK); hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, m.line(), m.col(), ns.getLiteralPath(), Utilities.existsInList(mc.scoring(), "proportion", "ratio", "continuous-variable", "cohort"), I18nConstants.MEASURE_MR_M_SCORING_UNK);
@ -299,8 +299,8 @@ public class MeasureValidator extends BaseValidator {
// but we still check that the code, if both have one, is consistent. // but we still check that the code, if both have one, is consistent.
Element mrg = glist.get(0); Element mrg = glist.get(0);
NodeStack ns = stack.push(mrg, 0, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition()); NodeStack ns = stack.push(mrg, 0, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition());
if (m.groups().get(0).hasCode() && mrg.hasChild("code")) { if (m.groups().get(0).hasCode() && mrg.hasChild("code", false)) {
CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code")); CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code", false));
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), hasUseableCode(cc), I18nConstants.MEASURE_MR_GRP_NO_USABLE_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), hasUseableCode(cc), I18nConstants.MEASURE_MR_GRP_NO_USABLE_CODE)) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc.matches(m.groups().get(0).getCode()), I18nConstants.MEASURE_MR_GRP_NO_WRONG_CODE, DataRenderer.display(context, cc), DataRenderer.display(context, m.groups().get(0).getCode())) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc.matches(m.groups().get(0).getCode()), I18nConstants.MEASURE_MR_GRP_NO_WRONG_CODE, DataRenderer.display(context, cc), DataRenderer.display(context, m.groups().get(0).getCode())) && ok;
} else { } else {
@ -312,7 +312,7 @@ public class MeasureValidator extends BaseValidator {
int i = 0; int i = 0;
for (Element mrg : glist) { for (Element mrg : glist) {
NodeStack ns = stack.push(mrg, i, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition()); NodeStack ns = stack.push(mrg, i, mrg.getProperty().getDefinition(), mrg.getProperty().getDefinition());
CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code")); CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrg.getNamedChild("code", false));
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_NO_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_NO_CODE)) {
MeasureGroupComponent mg = getGroupForCode(cc, m.measure()); MeasureGroupComponent mg = getGroupForCode(cc, m.measure());
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mg != null, I18nConstants.MEASURE_MR_GRP_UNK_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mg != null, I18nConstants.MEASURE_MR_GRP_UNK_CODE)) {
@ -355,7 +355,7 @@ public class MeasureValidator extends BaseValidator {
private boolean validateScore(ValidationContext hostContext, MeasureContext m, List<ValidationMessage> errors, Element mrg, NodeStack stack, boolean inProgress) { private boolean validateScore(ValidationContext hostContext, MeasureContext m, List<ValidationMessage> errors, Element mrg, NodeStack stack, boolean inProgress) {
boolean ok = true; boolean ok = true;
Element ms = mrg.getNamedChild("measureScore"); Element ms = mrg.getNamedChild("measureScore", false);
// first, we check MeasureReport.type // first, we check MeasureReport.type
if ("data-collection".equals(m.reportType())) { if ("data-collection".equals(m.reportType())) {
ok = banned(errors, stack, ms, I18nConstants.MEASURE_MR_SCORE_PROHIBITED_RT) && ok; ok = banned(errors, stack, ms, I18nConstants.MEASURE_MR_SCORE_PROHIBITED_RT) && ok;
@ -365,11 +365,11 @@ public class MeasureValidator extends BaseValidator {
} else if (Utilities.existsInList(m.scoring(), "proportion", "ratio", "continuous-variable")) { } else if (Utilities.existsInList(m.scoring(), "proportion", "ratio", "continuous-variable")) {
if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, mrg.line(), mrg.col(), stack.getLiteralPath(), ms != null, I18nConstants.MEASURE_MR_SCORE_REQUIRED, m.scoring())) { if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, mrg.line(), mrg.col(), stack.getLiteralPath(), ms != null, I18nConstants.MEASURE_MR_SCORE_REQUIRED, m.scoring())) {
NodeStack ns = stack.push(ms, -1, ms.getProperty().getDefinition(), ms.getProperty().getDefinition()); NodeStack ns = stack.push(ms, -1, ms.getProperty().getDefinition(), ms.getProperty().getDefinition());
Element v = ms.getNamedChild("value"); Element v = ms.getNamedChild("value", false);
// TODO: this is a DEQM special and should be handled differently // TODO: this is a DEQM special and should be handled differently
if (v == null) { if (v == null) {
if (ms.hasExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType")) { if (ms.hasExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType")) {
v = ms.getExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType").getNamedChild("value"); v = ms.getExtension("http://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-alternateScoreType").getNamedChild("value", false);
} }
} }
if ("proportion".equals(m.scoring())) { if ("proportion".equals(m.scoring())) {
@ -391,13 +391,13 @@ public class MeasureValidator extends BaseValidator {
} else if ("ratio".equals(m.scoring())) { } else if ("ratio".equals(m.scoring())) {
// ratio - score is a number with no value constraints, and maybe with a unit (perhaps constrained by extension) // ratio - score is a number with no value constraints, and maybe with a unit (perhaps constrained by extension)
if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "ratio")) { if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "ratio")) {
Element unit = ms.getNamedChild("code"); Element unit = ms.getNamedChild("code", false);
Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null; Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null;
if (unit != null) { if (unit != null) {
if (c != null) { if (c != null) {
NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition()); NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition());
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode()) && ok;
Element system = ms.getNamedChild("system"); Element system = ms.getNamedChild("system", false);
if (system == null) { if (system == null) {
NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition()); NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition());
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok;
@ -416,13 +416,13 @@ public class MeasureValidator extends BaseValidator {
} else if ("continuous-variable".equals(m.scoring())) { } else if ("continuous-variable".equals(m.scoring())) {
// continuous-variable - score is a quantity with a unit per the extension // continuous-variable - score is a quantity with a unit per the extension
if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "continuous-variable")) { if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, ms.line(), ms.col(), ns.getLiteralPath(), v != null, I18nConstants.MEASURE_MR_SCORE_VALUE_REQUIRED, "continuous-variable")) {
Element unit = ms.getNamedChild("code"); Element unit = ms.getNamedChild("code", false);
Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null; Coding c = m.measure().hasExtension(ToolingExtensions.EXT_Q_UNIT) ? (Coding) m.measure().getExtensionByUrl(ToolingExtensions.EXT_Q_UNIT).getValue() : null;
if (unit != null) { if (unit != null) {
if (c != null) { if (c != null) {
NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition()); NodeStack nsc = ns.push(unit, -1, unit.getProperty().getDefinition(), unit.getProperty().getDefinition());
rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode()); rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, unit.line(), unit.col(), nsc.getLiteralPath(), c.getCode().equals(unit.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getCode());
Element system = ms.getNamedChild("system"); Element system = ms.getNamedChild("system", false);
if (system == null) { if (system == null) {
NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition()); NodeStack nss = system == null ? ns : ns.push(system, -1, system.getProperty().getDefinition(), system.getProperty().getDefinition());
ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, system.line(), system.col(), nss.getLiteralPath(), c.getSystem().equals(system.primitiveValue()), I18nConstants.MEASURE_MR_SCORE_FIXED, c.getSystem()) && ok;
@ -443,7 +443,7 @@ public class MeasureValidator extends BaseValidator {
} }
private boolean banned(List<ValidationMessage> errors, NodeStack stack, Element parent, String childName, String msgId, Object... params) { private boolean banned(List<ValidationMessage> errors, NodeStack stack, Element parent, String childName, String msgId, Object... params) {
Element child = parent.getNamedChild(childName); Element child = parent.getNamedChild(childName, false);
return banned(errors, stack, child, msgId, params); return banned(errors, stack, child, msgId, params);
} }
@ -465,7 +465,7 @@ public class MeasureValidator extends BaseValidator {
int i = 0; int i = 0;
for (Element mrgp : plist) { for (Element mrgp : plist) {
NodeStack ns = stack.push(mrgp, i, mrgp.getProperty().getDefinition(), mrgp.getProperty().getDefinition()); NodeStack ns = stack.push(mrgp, i, mrgp.getProperty().getDefinition(), mrgp.getProperty().getDefinition());
CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgp.getNamedChild("code")); CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgp.getNamedChild("code", false));
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) {
MeasureGroupPopulationComponent mgp = getGroupPopForCode(cc, mg); MeasureGroupPopulationComponent mgp = getGroupPopForCode(cc, mg);
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgp != null, I18nConstants.MEASURE_MR_GRP_POP_UNK_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgp != null, I18nConstants.MEASURE_MR_GRP_POP_UNK_CODE)) {
@ -503,7 +503,7 @@ public class MeasureValidator extends BaseValidator {
} }
} else { } else {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), sr.size() == 0, I18nConstants.MEASURE_MR_GRP_POP_NO_SUBJECTS) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), sr.size() == 0, I18nConstants.MEASURE_MR_GRP_POP_NO_SUBJECTS) && ok;
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), mrgp.hasChild("count"), I18nConstants.MEASURE_MR_GRP_POP_NO_COUNT); warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgp.line(), mrgp.col(), ns.getLiteralPath(), mrgp.hasChild("count", false), I18nConstants.MEASURE_MR_GRP_POP_NO_COUNT);
} }
return ok; return ok;
} }
@ -518,7 +518,7 @@ public class MeasureValidator extends BaseValidator {
int i = 0; int i = 0;
for (Element mrgs : slist) { for (Element mrgs : slist) {
NodeStack ns = stack.push(mrgs, i, mrgs.getProperty().getDefinition(), mrgs.getProperty().getDefinition()); NodeStack ns = stack.push(mrgs, i, mrgs.getProperty().getDefinition(), mrgs.getProperty().getDefinition());
CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgs.getNamedChild("code")); CodeableConcept cc = ObjectConverter.readAsCodeableConcept(mrgs.getNamedChild("code", false));
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgs.line(), mrgs.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrgs.line(), mrgs.col(), ns.getLiteralPath(), cc != null, I18nConstants.MEASURE_MR_GRP_POP_NO_CODE)) {
MeasureGroupStratifierComponent mgs = getGroupStratifierForCode(cc, mg); MeasureGroupStratifierComponent mgs = getGroupStratifierForCode(cc, mg);
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgs != null, I18nConstants.MEASURE_MR_GRPST_POP_UNK_CODE)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, mrg.line(), mrg.col(), ns.getLiteralPath(), mgs != null, I18nConstants.MEASURE_MR_GRPST_POP_UNK_CODE)) {

View File

@ -29,18 +29,18 @@ public class ObservationValidator extends BaseValidator {
boolean ok = true; boolean ok = true;
// all observations should have a subject, a performer, and a time // all observations should have a subject, a performer, and a time
ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), element.getNamedChild("subject") != null, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_SUBJECT) && ok; ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), element.getNamedChild("subject", false) != null, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_SUBJECT) && ok;
List<Element> performers = new ArrayList<>(); List<Element> performers = new ArrayList<>();
element.getNamedChildren("performer", performers); element.getNamedChildren("performer", performers);
ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), performers.size() > 0, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_PERFORMER) && ok; ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), performers.size() > 0, I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_A_PERFORMER) && ok;
ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), ok = bpCheck(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
element.getNamedChild("effectiveDateTime") != null || element.getNamedChild("effectivePeriod") != null || element.getNamedChild("effectiveDateTime", false) != null || element.getNamedChild("effectivePeriod", false) != null ||
element.getNamedChild("effectiveTiming") != null || element.getNamedChild("effectiveInstant") != null, element.getNamedChild("effectiveTiming", false) != null || element.getNamedChild("effectiveInstant", false) != null,
I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok; I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok;
// hook in the vital signs // hook in the vital signs
if (VersionUtilities.isR4Plus(context.getVersion())) { if (VersionUtilities.isR4Plus(context.getVersion())) {
Element code = element.getNamedChild("code"); Element code = element.getNamedChild("code", false);
List<String> codes = new ArrayList<>(); List<String> codes = new ArrayList<>();
if (hasLoincCode(code, codes, "85353-1")) { if (hasLoincCode(code, codes, "85353-1")) {
ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes, pct, mode) && ok; ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes, pct, mode) && ok;
@ -102,8 +102,8 @@ public class ObservationValidator extends BaseValidator {
if (code != null) { if (code != null) {
List<Element> codings = code.getChildren("coding"); List<Element> codings = code.getChildren("coding");
for (Element coding : codings) { for (Element coding : codings) {
if ("http://loinc.org".equals(coding.getNamedChildValue("system")) && Utilities.existsInList(coding.getNamedChildValue("code"), values)) { if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
codes.add(coding.getNamedChildValue("code")); codes.add(coding.getNamedChildValue("code", false));
return true; return true;
} }
} }
@ -115,8 +115,8 @@ public class ObservationValidator extends BaseValidator {
if (code != null) { if (code != null) {
List<Element> codings = code.getChildren("coding"); List<Element> codings = code.getChildren("coding");
for (Element coding : codings) { for (Element coding : codings) {
if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system")) && Utilities.existsInList(coding.getNamedChildValue("code"), values)) { if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
codes.add(coding.getNamedChildValue("code")); codes.add(coding.getNamedChildValue("code", false));
return true; return true;
} }
} }

View File

@ -154,11 +154,11 @@ public class QuestionnaireValidator extends BaseValidator {
Element ext = e.getExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-derivationType"); Element ext = e.getExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-derivationType");
if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, ext != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE, url)) { if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, ext != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE, url)) {
NodeStack next = ns.push(ext, -1, ext.getProperty().getDefinition(), ext.getProperty().getDefinition()); NodeStack next = ns.push(ext, -1, ext.getProperty().getDefinition(), ext.getProperty().getDefinition());
Element v = ext.getNamedChild("value"); Element v = ext.getNamedChild("value", false);
if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, next, v != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE_VALUE)) { if (warning(errors, "2023-06-15", IssueType.BUSINESSRULE, next, v != null, I18nConstants.QUESTIONNAIRE_Q_NO_DERIVATION_TYPE_VALUE)) {
NodeStack nv = next.push(v, -1, v.getProperty().getDefinition(), v.getProperty().getDefinition()); NodeStack nv = next.push(v, -1, v.getProperty().getDefinition(), v.getProperty().getDefinition());
String s = v.getNamedChildValue("system"); String s = v.getNamedChildValue("system", false);
String c = v.getNamedChildValue("code"); String c = v.getNamedChildValue("code", false);
if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "extends".equals(c)) { if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "extends".equals(c)) {
derivations.add(new QuestionnaireDerivation(q, QuestionnaireDerivationMode.EXTENDS)); derivations.add(new QuestionnaireDerivation(q, QuestionnaireDerivationMode.EXTENDS));
} else if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "compliesWith".equals(c)) { } else if ("http://hl7.org/fhir/questionnaire-derivationType".equals(s) && "compliesWith".equals(c)) {
@ -196,7 +196,7 @@ public class QuestionnaireValidator extends BaseValidator {
if ((VersionUtilities.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) { if ((VersionUtilities.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) {
List<Element> ewl = item.getChildren("enableWhen"); List<Element> ewl = item.getChildren("enableWhen");
for (Element ew : ewl) { for (Element ew : ewl) {
String ql = ew.getNamedChildValue("question"); String ql = ew.getNamedChildValue("question", false);
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, ql != null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_NOLINK)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, ql != null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_NOLINK)) {
Element tgt = getQuestionById(item, ql); Element tgt = getQuestionById(item, ql);
if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, tgt == null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_ISINNER)) { if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, ns, tgt == null, I18nConstants.QUESTIONNAIRE_Q_ENABLEWHEN_ISINNER)) {
@ -228,7 +228,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean validateQuestionnaireElementDerivation(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, QuestionnaireDerivation derivation) { private boolean validateQuestionnaireElementDerivation(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, QuestionnaireDerivation derivation) {
boolean ok = true; boolean ok = true;
String linkId = item.getNamedChildValue("linkId"); String linkId = item.getNamedChildValue("linkId", false);
QuestionnaireItemComponent qi = derivation.questionnaire.getQuestion(linkId); QuestionnaireItemComponent qi = derivation.questionnaire.getQuestion(linkId);
if (qi == null) { if (qi == null) {
ok = rule(errors, "2023-06-15", IssueType.NOTFOUND, ns.getLiteralPath(), derivation.mode == QuestionnaireDerivationMode.EXTENDS, I18nConstants.QUESTIONNAIRE_Q_ITEM_NOT_DERIVED, derivation.questionnaire.getUrl(), linkId) && ok; ok = rule(errors, "2023-06-15", IssueType.NOTFOUND, ns.getLiteralPath(), derivation.mode == QuestionnaireDerivationMode.EXTENDS, I18nConstants.QUESTIONNAIRE_Q_ITEM_NOT_DERIVED, derivation.questionnaire.getUrl(), linkId) && ok;
@ -237,7 +237,7 @@ public class QuestionnaireValidator extends BaseValidator {
// type must be the same // type must be the same
if (qi.hasType()) { if (qi.hasType()) {
Element e = item.getNamedChild("type"); Element e = item.getNamedChild("type", false);
if (e != null) { if (e != null) {
NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition());
ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, qi.getType().toCode().equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_TYPE, derivation.questionnaire.getUrl(), linkId, qi.getType().toCode(), e.primitiveValue()) && ok; ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, qi.getType().toCode().equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_TYPE, derivation.questionnaire.getUrl(), linkId, qi.getType().toCode(), e.primitiveValue()) && ok;
@ -246,7 +246,7 @@ public class QuestionnaireValidator extends BaseValidator {
// if it doesn't repeat, it can't start repeating // if it doesn't repeat, it can't start repeating
if (!qi.getRepeats()) { if (!qi.getRepeats()) {
Element e = item.getNamedChild("repeats"); Element e = item.getNamedChild("repeats", false);
if (e != null) { if (e != null) {
NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition());
ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, !"true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REPEATS, derivation.questionnaire.getUrl(), linkId) && ok; ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, !"true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REPEATS, derivation.questionnaire.getUrl(), linkId) && ok;
@ -255,7 +255,7 @@ public class QuestionnaireValidator extends BaseValidator {
// if it is required, it can't become un-required // if it is required, it can't become un-required
if (qi.getRequired()) { if (qi.getRequired()) {
Element e = item.getNamedChild("required"); Element e = item.getNamedChild("required", false);
if (e != null) { if (e != null) {
NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition());
ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REQUIRED, derivation.questionnaire.getUrl(), linkId) && ok; ok = rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_REQUIRED, derivation.questionnaire.getUrl(), linkId) && ok;
@ -264,7 +264,7 @@ public class QuestionnaireValidator extends BaseValidator {
// if it has a definition, it shouldn't change // if it has a definition, it shouldn't change
if (qi.hasDefinition()) { if (qi.hasDefinition()) {
Element e = item.getNamedChild("definition"); Element e = item.getNamedChild("definition", false);
if (e != null) { if (e != null) {
NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition());
hint(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_DEFINITION, derivation.questionnaire.getUrl(), linkId, qi.getDefinition()); hint(errors, "2023-06-15", IssueType.BUSINESSRULE, ne, "true".equals(e.primitiveValue()), I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_DEFINITION, derivation.questionnaire.getUrl(), linkId, qi.getDefinition());
@ -275,7 +275,7 @@ public class QuestionnaireValidator extends BaseValidator {
// if it has maxLength, that can't get longer // if it has maxLength, that can't get longer
if (qi.hasMaxLength()) { if (qi.hasMaxLength()) {
Element e = item.getNamedChild("maxlength"); Element e = item.getNamedChild("maxlength", false);
if (e != null) { if (e != null) {
NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition()); NodeStack ne = ns.push(e, -1, e.getProperty().getDefinition(), e.getProperty().getDefinition());
int ml = Utilities.parseInt(e.primitiveValue(), 0); int ml = Utilities.parseInt(e.primitiveValue(), 0);
@ -286,7 +286,7 @@ public class QuestionnaireValidator extends BaseValidator {
} }
if (qi.hasAnswerOption()) { if (qi.hasAnswerOption()) {
Element e = item.getNamedChild("answerValueSet"); Element e = item.getNamedChild("answerValueSet", false);
if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "Option", "ValueSet")) { if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "Option", "ValueSet")) {
// for each answer option here, there must be a matching answer option in the source // for each answer option here, there must be a matching answer option in the source
List<Element> list = new ArrayList<>(); List<Element> list = new ArrayList<>();
@ -295,7 +295,7 @@ public class QuestionnaireValidator extends BaseValidator {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
Element ao = list.get(i); Element ao = list.get(i);
NodeStack nao = ns.push(ao, i, ao.getProperty().getDefinition(), ao.getProperty().getDefinition()); NodeStack nao = ns.push(ao, i, ao.getProperty().getDefinition(), ao.getProperty().getDefinition());
Element v = ao.getNamedChild("value"); Element v = ao.getNamedChild("value", false);
if (v != null) { if (v != null) {
boolean aok = false; boolean aok = false;
switch (v.fhirType()) { switch (v.fhirType()) {
@ -312,10 +312,10 @@ public class QuestionnaireValidator extends BaseValidator {
aok = findAOPrimitive(qi.getAnswerOption(), "string", v.primitiveValue()); aok = findAOPrimitive(qi.getAnswerOption(), "string", v.primitiveValue());
break; break;
case "Coding": case "Coding":
aok = findAOCoding(qi.getAnswerOption(), new Coding().setSystem(v.getNamedChildValue("system")).setVersion(v.getNamedChildValue("version")).setCode(v.getNamedChildValue("code"))); aok = findAOCoding(qi.getAnswerOption(), new Coding().setSystem(v.getNamedChildValue("system", false)).setVersion(v.getNamedChildValue("version", false)).setCode(v.getNamedChildValue("code", false)));
break; break;
case "Reference": case "Reference":
aok = findAOReference(qi.getAnswerOption(), new Reference().setReference(v.getNamedChildValue("reference"))); aok = findAOReference(qi.getAnswerOption(), new Reference().setReference(v.getNamedChildValue("reference", false)));
break; break;
} }
ok= rule(errors, "2023-06-15", IssueType.BUSINESSRULE, nao, aok, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_ANSWER_OPTIONS_NEW, derivation.questionnaire.getUrl(), linkId) && ok; ok= rule(errors, "2023-06-15", IssueType.BUSINESSRULE, nao, aok, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_ANSWER_OPTIONS_NEW, derivation.questionnaire.getUrl(), linkId) && ok;
@ -329,7 +329,7 @@ public class QuestionnaireValidator extends BaseValidator {
} }
} }
if (qi.hasAnswerValueSet()) { if (qi.hasAnswerValueSet()) {
Element e = item.getNamedChild("answerOption"); Element e = item.getNamedChild("answerOption", false);
if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "ValueSet", "Option")) { if (rule(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NC_ANSWER_TYPE, derivation.questionnaire.getUrl(), linkId, "ValueSet", "Option")) {
warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NI_ANSWER_VS, derivation.questionnaire.getUrl(), linkId); warning(errors, "2023-06-15", IssueType.BUSINESSRULE, ns, e == null, I18nConstants.QUESTIONNAIRE_Q_ITEM_DERIVED_NI_ANSWER_VS, derivation.questionnaire.getUrl(), linkId);
} else { } else {
@ -415,7 +415,7 @@ public class QuestionnaireValidator extends BaseValidator {
private Element getQuestionById(Element focus, String ql) { private Element getQuestionById(Element focus, String ql) {
List<Element> list = getItems(focus); List<Element> list = getItems(focus);
for (Element item : list) { for (Element item : list) {
String v = item.getNamedChildValue("linkId"); String v = item.getNamedChildValue("linkId", false);
if (ql.equals(v)) if (ql.equals(v))
return item; return item;
Element tgt = getQuestionById(item, ql); Element tgt = getQuestionById(item, ql);
@ -437,7 +437,7 @@ public class QuestionnaireValidator extends BaseValidator {
return true; return true;
} }
boolean ok = true; boolean ok = true;
Element q = element.getNamedChild("questionnaire"); Element q = element.getNamedChild("questionnaire", false);
String questionnaire = null; String questionnaire = null;
if (q != null) { if (q != null) {
/* /*
@ -475,7 +475,7 @@ public class QuestionnaireValidator extends BaseValidator {
qok = warning(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); qok = warning(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire);
} }
if (qok) { if (qok) {
boolean inProgress = "in-progress".equals(element.getNamedChildValue("status")); boolean inProgress = "in-progress".equals(element.getNamedChildValue("status", false));
ok = validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.q().getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element)) && ok; ok = validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.q().getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element)) && ok;
} }
} }
@ -485,7 +485,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean validateQuestionnaireResponseItem(ValidationContext hostContext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) { private boolean validateQuestionnaireResponseItem(ValidationContext hostContext, QuestionnaireWithContext qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
BooleanHolder ok = new BooleanHolder(); BooleanHolder ok = new BooleanHolder();
String text = element.getNamedChildValue("text"); String text = element.getNamedChildValue("text", false);
ok.see(rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), I18nConstants.QUESTIONNAIRE_QR_ITEM_TEXT, qItem.getLinkId())); ok.see(rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), I18nConstants.QUESTIONNAIRE_QR_ITEM_TEXT, qItem.getLinkId()));
List<Element> answers = new ArrayList<Element>(); List<Element> answers = new ArrayList<Element>();
@ -638,7 +638,7 @@ public class QuestionnaireValidator extends BaseValidator {
int lastIndex = -1; int lastIndex = -1;
int counter = 0; int counter = 0;
for (Element item : items) { for (Element item : items) {
String linkId = item.getNamedChildValue("linkId"); String linkId = item.getNamedChildValue("linkId", false);
if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), I18nConstants.QUESTIONNAIRE_QR_ITEM_NOLINKID)) { if (rule(errors, NO_RULE_DATE, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), I18nConstants.QUESTIONNAIRE_QR_ITEM_NOLINKID)) {
int index = getLinkIdIndex(qItems, linkId); int index = getLinkIdIndex(qItems, linkId);
if (index == -1) { if (index == -1) {
@ -799,7 +799,7 @@ public class QuestionnaireValidator extends BaseValidator {
} }
private boolean validateAnswerCode(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean theOpenChoice) { private boolean validateAnswerCode(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean theOpenChoice) {
Element v = answer.getNamedChild("valueCoding"); Element v = answer.getNamedChild("valueCoding", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) if (qItem.getAnswerOption().size() > 0)
checkCodingOption(errors, answer, stack, qSrc, qItem, theOpenChoice); checkCodingOption(errors, answer, stack, qSrc, qItem, theOpenChoice);
@ -826,7 +826,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean checkIntegerOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { private boolean checkIntegerOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) {
boolean ok = true; boolean ok = true;
Element v = answer.getNamedChild("valueInteger"); Element v = answer.getNamedChild("valueInteger", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) { if (qItem.getAnswerOption().size() > 0) {
List<IntegerType> list = new ArrayList<IntegerType>(); List<IntegerType> list = new ArrayList<IntegerType>();
@ -859,7 +859,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean checkDateOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { private boolean checkDateOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) {
boolean ok = true; boolean ok = true;
Element v = answer.getNamedChild("valueDate"); Element v = answer.getNamedChild("valueDate", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) { if (qItem.getAnswerOption().size() > 0) {
List<DateType> list = new ArrayList<DateType>(); List<DateType> list = new ArrayList<DateType>();
@ -892,7 +892,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean checkTimeOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { private boolean checkTimeOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) {
boolean ok = true; boolean ok = true;
Element v = answer.getNamedChild("valueTime"); Element v = answer.getNamedChild("valueTime", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) { if (qItem.getAnswerOption().size() > 0) {
List<TimeType> list = new ArrayList<TimeType>(); List<TimeType> list = new ArrayList<TimeType>();
@ -925,7 +925,7 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean checkStringOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { private boolean checkStringOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) {
boolean ok = true; boolean ok = true;
Element v = answer.getNamedChild("valueString"); Element v = answer.getNamedChild("valueString", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) { if (qItem.getAnswerOption().size() > 0) {
List<StringType> list = new ArrayList<StringType>(); List<StringType> list = new ArrayList<StringType>();
@ -963,9 +963,9 @@ public class QuestionnaireValidator extends BaseValidator {
private boolean checkCodingOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) { private boolean checkCodingOption(List<ValidationMessage> errors, Element answer, NodeStack stack, QuestionnaireWithContext qSrc, QuestionnaireItemComponent qItem, boolean openChoice) {
boolean ok = true; boolean ok = true;
Element v = answer.getNamedChild("valueCoding"); Element v = answer.getNamedChild("valueCoding", false);
String system = v.getNamedChildValue("system"); String system = v.getNamedChildValue("system", false);
String code = v.getNamedChildValue("code"); String code = v.getNamedChildValue("code", false);
NodeStack ns = stack.push(v, -1, null, null); NodeStack ns = stack.push(v, -1, null, null);
if (qItem.getAnswerOption().size() > 0) { if (qItem.getAnswerOption().size() > 0) {
List<Coding> list = new ArrayList<Coding>(); List<Coding> list = new ArrayList<Coding>();

View File

@ -42,14 +42,14 @@ public class SearchParameterValidator extends BaseValidator {
boolean ok = true; boolean ok = true;
// String url = cs.getNamedChildValue("url"); // String url = cs.getNamedChildValue("url");
if (cs.hasChild("expression")) { if (cs.hasChild("expression", false)) {
List<String> bases = new ArrayList<>(); List<String> bases = new ArrayList<>();
for (Element b : cs.getChildrenByName("base")) { for (Element b : cs.getChildrenByName("base")) {
bases.add(b.primitiveValue()); bases.add(b.primitiveValue());
} }
ok = checkExpression(errors, stack.push(cs.getNamedChild("expression"), -1, null, null), cs.getNamedChildValue("expression"), bases) && ok; ok = checkExpression(errors, stack.push(cs.getNamedChild("expression", false), -1, null, null), cs.getNamedChildValue("expression", false), bases) && ok;
} }
String master = cs.getNamedChildValue("derivedFrom"); String master = cs.getNamedChildValue("derivedFrom", false);
if (!Utilities.noString(master)) { if (!Utilities.noString(master)) {
SearchParameter sp = context.fetchResource(SearchParameter.class, master); SearchParameter sp = context.fetchResource(SearchParameter.class, master);
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp != null, I18nConstants.SEARCHPARAMETER_NOTFOUND, master)) { if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp != null, I18nConstants.SEARCHPARAMETER_NOTFOUND, master)) {
@ -58,15 +58,15 @@ public class SearchParameterValidator extends BaseValidator {
for (Element b : bl) { for (Element b : bl) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp.hasBase(b.primitiveValue()) || sp.hasBase("Resource"), I18nConstants.SEARCHPARAMETER_BASE_WRONG, master, b.primitiveValue()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), sp.hasBase(b.primitiveValue()) || sp.hasBase("Resource"), I18nConstants.SEARCHPARAMETER_BASE_WRONG, master, b.primitiveValue()) && ok;
} }
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), !cs.hasChild("type") || sp.getType().toCode().equals(cs.getNamedChildValue("type")), I18nConstants.SEARCHPARAMETER_TYPE_WRONG, master, sp.getType().toCode(), cs.getNamedChildValue("type")) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), !cs.hasChild("type", false) || sp.getType().toCode().equals(cs.getNamedChildValue("type", false)), I18nConstants.SEARCHPARAMETER_TYPE_WRONG, master, sp.getType().toCode(), cs.getNamedChildValue("type", false)) && ok;
if (sp.hasExpression() && cs.hasChild("expression") && !sp.getExpression().equals(cs.getNamedChildValue("expression"))) { if (sp.hasExpression() && cs.hasChild("expression", false) && !sp.getExpression().equals(cs.getNamedChildValue("expression", false))) {
List<String> bases = new ArrayList<>(); List<String> bases = new ArrayList<>();
for (Element b : cs.getChildren("base")) { for (Element b : cs.getChildren("base")) {
bases.add(b.primitiveValue()); bases.add(b.primitiveValue());
} }
String expThis = canonicalise(cs.getNamedChildValue("expression"), bases); String expThis = canonicalise(cs.getNamedChildValue("expression", false), bases);
String expOther = canonicalise(sp.getExpression(), bases); String expOther = canonicalise(sp.getExpression(), bases);
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), expThis.equals(expOther), I18nConstants.SEARCHPARAMETER_EXP_WRONG, master, sp.getExpression(), cs.getNamedChildValue("expression")); warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE,stack.getLiteralPath(), expThis.equals(expOther), I18nConstants.SEARCHPARAMETER_EXP_WRONG, master, sp.getExpression(), cs.getNamedChildValue("expression", false));
} }
// todo: check compositions // todo: check compositions

View File

@ -76,7 +76,7 @@ public class StructureDefinitionValidator extends BaseValidator {
StructureDefinition sd = null; StructureDefinition sd = null;
String typeName = null; String typeName = null;
try { try {
String url = src.getNamedChildValue("url"); String url = src.getNamedChildValue("url", false);
sd = loadAsSD(src); sd = loadAsSD(src);
ok = checkExtensionContext(errors, src, stack) && ok; ok = checkExtensionContext(errors, src, stack) && ok;
@ -131,22 +131,22 @@ public class StructureDefinitionValidator extends BaseValidator {
List<Element> differentials = src.getChildrenByName("differential"); List<Element> differentials = src.getChildrenByName("differential");
List<Element> snapshots = src.getChildrenByName("snapshot"); List<Element> snapshots = src.getChildrenByName("snapshot");
boolean logical = "logical".equals(src.getNamedChildValue("kind")); boolean logical = "logical".equals(src.getNamedChildValue("kind", false));
boolean constraint = "constraint".equals(src.getNamedChildValue("derivation")); boolean constraint = "constraint".equals(src.getNamedChildValue("derivation", false));
for (Element differential : differentials) { for (Element differential : differentials) {
ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type"), src.getNamedChildValue("url"), src.getNamedChildValue("type"), base) && ok; ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok;
} }
for (Element snapshotE : snapshots) { for (Element snapshotE : snapshots) {
ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type"), src.getNamedChildValue("url"), src.getNamedChildValue("type"), base) && ok; ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok;
} }
// obligation profile support // obligation profile support
if (src.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) { if (src.hasExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG)) {
Element ext = src.getExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG); Element ext = src.getExtension(ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG);
Element value = ext.getNamedChild("value"); Element value = ext.getNamedChild("value", false);
if (value != null && "true".equals(value.primitiveValue())) { if (value != null && "true".equals(value.primitiveValue())) {
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), "constraint".equals(src.getNamedChildValue("derivation")), I18nConstants.SD_OBGLIGATION_PROFILE_DERIVATION)) { if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), "constraint".equals(src.getNamedChildValue("derivation", false)), I18nConstants.SD_OBGLIGATION_PROFILE_DERIVATION)) {
if (warning(errors, "2023-05-27", IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.SD_OBGLIGATION_PROFILE_UKNOWN, src.getNamedChildValue("baseDefinition"))) { if (warning(errors, "2023-05-27", IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.SD_OBGLIGATION_PROFILE_UKNOWN, src.getNamedChildValue("baseDefinition", false))) {
for (Element differential : differentials) { for (Element differential : differentials) {
ok = validateObligationProfile(errors, differential, stack.push(differential, -1, null, null), base) && ok; ok = validateObligationProfile(errors, differential, stack.push(differential, -1, null, null), base) && ok;
} }
@ -160,7 +160,7 @@ public class StructureDefinitionValidator extends BaseValidator {
List<Element> extensions = src.getChildren("extension"); List<Element> extensions = src.getChildren("extension");
int c = 0; int c = 0;
for (Element extension : extensions) { for (Element extension : extensions) {
if (ToolingExtensions.EXT_OBLIGATION_INHERITS.equals(extension.getNamedChildValue("url"))) { if (ToolingExtensions.EXT_OBLIGATION_INHERITS.equals(extension.getNamedChildValue("url", false))) {
ok = validateInheritsObligationProfile(errors, extension, stack.push(extension, c, null, null), src) && ok; ok = validateInheritsObligationProfile(errors, extension, stack.push(extension, c, null, null), src) && ok;
} }
c++; c++;
@ -174,9 +174,9 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
// if this is defining an extension, make sure that the extension fixed value matches the URL // if this is defining an extension, make sure that the extension fixed value matches the URL
String type = src.getNamedChildValue("type"); String type = src.getNamedChildValue("type", false);
if ("Extension".equals(type)) { if ("Extension".equals(type)) {
String baseD = src.getNamedChildValue("baseDefinition"); String baseD = src.getNamedChildValue("baseDefinition", false);
if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(baseD) && url != null) { if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(baseD) && url != null) {
String fixedUrl = getFixedValue(src); String fixedUrl = getFixedValue(src);
if (rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), fixedUrl != null, I18nConstants.SD_EXTENSION_URL_MISSING, url)) { if (rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), fixedUrl != null, I18nConstants.SD_EXTENSION_URL_MISSING, url)) {
@ -195,12 +195,12 @@ public class StructureDefinitionValidator extends BaseValidator {
private String getFixedValue(Element src) { private String getFixedValue(Element src) {
Element diff = src.getNamedChild("differential"); Element diff = src.getNamedChild("differential", false);
if (diff != null) { if (diff != null) {
for (Element ed : diff.getChildrenByName("element")) { for (Element ed : diff.getChildrenByName("element")) {
String path = ed.getNamedChildValue("path"); String path = ed.getNamedChildValue("path", false);
if ("Extension.url".equals(path)) { if ("Extension.url".equals(path)) {
return ed.getNamedChildValue("fixed"); return ed.getNamedChildValue("fixed", false);
} }
} }
} }
@ -208,7 +208,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
private boolean validateInheritsObligationProfile(List<ValidationMessage> errors, Element extension, NodeStack stack, Element src) { private boolean validateInheritsObligationProfile(List<ValidationMessage> errors, Element extension, NodeStack stack, Element src) {
String tgt = extension.getNamedChildValue("value"); String tgt = extension.getNamedChildValue("value", false);
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), tgt != null, if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), tgt != null,
I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NO_TARGET)) { I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NO_TARGET)) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, tgt); StructureDefinition sd = context.fetchResource(StructureDefinition.class, tgt);
@ -216,7 +216,7 @@ public class StructureDefinitionValidator extends BaseValidator {
I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_TARGET_NOT_FOUND, tgt)) { I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_TARGET_NOT_FOUND, tgt)) {
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), ToolingExtensions.readBoolExtension(sd, ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG), if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), ToolingExtensions.readBoolExtension(sd, ToolingExtensions.EXT_OBLIGATION_PROFILE_FLAG),
I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_TYPE, tgt)) { I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_TYPE, tgt)) {
String base = src.getNamedChildValue("baseDefinition"); String base = src.getNamedChildValue("baseDefinition", false);
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), base != null && base.equals(sd.getBaseDefinition()), if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), base != null && base.equals(sd.getBaseDefinition()),
I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_BASE, tgt, sd.getBaseDefinition(), base)) { I18nConstants.SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_BASE, tgt, sd.getBaseDefinition(), base)) {
return true; return true;
@ -241,7 +241,7 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean validateObligationProfileElement(List<ValidationMessage> errors, Element element, NodeStack push, StructureDefinition base) { private boolean validateObligationProfileElement(List<ValidationMessage> errors, Element element, NodeStack push, StructureDefinition base) {
// rules: it must exist in the base snapshot // rules: it must exist in the base snapshot
// it must only add must-support, obligations and extra bindings // it must only add must-support, obligations and extra bindings
String id = element.getNamedChildValue("id"); String id = element.getNamedChildValue("id", false);
ElementDefinition bd = base.getSnapshot().getElementById(id); ElementDefinition bd = base.getSnapshot().getElementById(id);
if (rule(errors, "2023-05-27", IssueType.INVALID, push.getLiteralPath(), bd != null, I18nConstants.SD_OBGLIGATION_PROFILE_UNMATCHED, id, base.getVersionedUrl())) { if (rule(errors, "2023-05-27", IssueType.INVALID, push.getLiteralPath(), bd != null, I18nConstants.SD_OBGLIGATION_PROFILE_UNMATCHED, id, base.getVersionedUrl())) {
boolean ok = true; boolean ok = true;
@ -256,7 +256,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
NodeStack stack = push.push(child, c, null, null); NodeStack stack = push.push(child, c, null, null);
if (child.getName().equals("extension")) { if (child.getName().equals("extension")) {
String url = child.getNamedChildValue("url"); String url = child.getNamedChildValue("url", false);
if (Utilities.existsInList(url, ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { if (Utilities.existsInList(url, ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) {
// this is ok, and it doesn't matter what's in the obligation // this is ok, and it doesn't matter what's in the obligation
} else { } else {
@ -304,11 +304,11 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
NodeStack stack = nstack.push(child, c, null, null); NodeStack stack = nstack.push(child, c, null, null);
if (child.getName().equals("extension")) { if (child.getName().equals("extension")) {
String url = child.getNamedChildValue("url"); String url = child.getNamedChildValue("url", false);
if ("http://hl7.org/fhir/tools/StructureDefinition/additional-binding".equals(url) && !VersionUtilities.isR5Plus(context.getVersion())) { if ("http://hl7.org/fhir/tools/StructureDefinition/additional-binding".equals(url) && !VersionUtilities.isR5Plus(context.getVersion())) {
Element purpose = child.getExtension("purpose"); Element purpose = child.getExtension("purpose");
if (purpose != null) { // should be an error elsewhere if (purpose != null) { // should be an error elsewhere
String code = purpose.getNamedChildValue("value"); String code = purpose.getNamedChildValue("value", false);
ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"), ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"),
I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok; I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok;
@ -319,7 +319,7 @@ public class StructureDefinitionValidator extends BaseValidator {
I18nConstants.SD_OBGLIGATION_PROFILE_ILLEGAL, id, child.getName()+"#"+url); I18nConstants.SD_OBGLIGATION_PROFILE_ILLEGAL, id, child.getName()+"#"+url);
} }
} else if (child.getName().equals("additional") && VersionUtilities.isR5Plus(context.getVersion())) { } else if (child.getName().equals("additional") && VersionUtilities.isR5Plus(context.getVersion())) {
String code = child.getNamedChildValue("purpose"); String code = child.getNamedChildValue("purpose", false);
ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"), ok = rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), !Utilities.existsInList(code, "maximum", "required", "extensible"),
I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok; I18nConstants.SD_OBGLIGATION_PROFILE_INVALID_BINDING_CODE, id, code) && ok;
} else if (child.getName().equals("strength")) { } else if (child.getName().equals("strength")) {
@ -339,7 +339,7 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean checkExtensionContext(List<ValidationMessage> errors, Element src, NodeStack stack) { private boolean checkExtensionContext(List<ValidationMessage> errors, Element src, NodeStack stack) {
boolean ok = true; boolean ok = true;
String type = src.getNamedChildValue("type"); String type = src.getNamedChildValue("type", false);
List<Element> eclist = src.getChildren("context"); List<Element> eclist = src.getChildren("context");
List<Element> cilist = src.getChildren("contextInvariant"); List<Element> cilist = src.getChildren("contextInvariant");
int i = 0; int i = 0;
@ -349,14 +349,14 @@ public class StructureDefinitionValidator extends BaseValidator {
String ct = null; String ct = null;
String cv = null; String cv = null;
if (VersionUtilities.isR4Plus(context.getVersion())) { if (VersionUtilities.isR4Plus(context.getVersion())) {
ct = ec.getNamedChildValue("type"); ct = ec.getNamedChildValue("type", false);
cv = ec.getNamedChildValue("expression"); cv = ec.getNamedChildValue("expression", false);
} else { } else {
ct = src.getNamedChildValue("contextType"); /// todo - this doesn't have the right value ct = src.getNamedChildValue("contextType", false); /// todo - this doesn't have the right value
cv = ec.primitiveValue(); cv = ec.primitiveValue();
} }
if ("element".equals(ct) && "Element".equals(cv)) { if ("element".equals(ct) && "Element".equals(cv)) {
warning(errors, "2023-04-23", IssueType.BUSINESSRULE, n.getLiteralPath(), false, I18nConstants.SD_CONTEXT_SHOULD_NOT_BE_ELEMENT, cv, src.getNamedChildValue("id")); warning(errors, "2023-04-23", IssueType.BUSINESSRULE, n.getLiteralPath(), false, I18nConstants.SD_CONTEXT_SHOULD_NOT_BE_ELEMENT, cv, src.getNamedChildValue("id", false));
} }
} else { } else {
ok = rule(errors, "2023-04-23", IssueType.INVALID, n.getLiteralPath(), false, I18nConstants.SD_NO_CONTEXT_WHEN_NOT_EXTENSION, type) && ok; ok = rule(errors, "2023-04-23", IssueType.INVALID, n.getLiteralPath(), false, I18nConstants.SD_NO_CONTEXT_WHEN_NOT_EXTENSION, type) && ok;
@ -389,12 +389,12 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean validateElementDefinition(List<ValidationMessage> errors, List<Element> elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map<String, String> invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base) { private boolean validateElementDefinition(List<ValidationMessage> errors, List<Element> elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map<String, String> invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base) {
boolean ok = true; boolean ok = true;
boolean typeMustSupport = false; boolean typeMustSupport = false;
String path = element.getNamedChildValue("path"); String path = element.getNamedChildValue("path", false);
ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), typeName == null || path == null || path.equals(typeName) || path.startsWith(typeName+"."), I18nConstants.SD_PATH_TYPE_MISMATCH, typeName, path) && ok; ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), typeName == null || path == null || path.equals(typeName) || path.startsWith(typeName+"."), I18nConstants.SD_PATH_TYPE_MISMATCH, typeName, path) && ok;
if (!snapshot) { if (!snapshot) {
ok = rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing"), I18nConstants.SD_NO_SLICING_ON_ROOT, path) && ok; ok = rule(errors, "2023-01-17", IssueType.INVALID, stack.getLiteralPath(), path.contains(".") || !element.hasChild("slicing", false), I18nConstants.SD_NO_SLICING_ON_ROOT, path) && ok;
} }
ok = rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), snapshot || !constraint || !element.hasChild("meaningWhenMissing") || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path) && ok; ok = rule(errors, "2023-05-22", IssueType.NOTFOUND, stack.getLiteralPath(), snapshot || !constraint || !element.hasChild("meaningWhenMissing", false) || meaningWhenMissingAllowed(element), I18nConstants.SD_ELEMENT_NOT_IN_CONSTRAINT, "meaningWhenMissing", path) && ok;
List<Element> types = element.getChildrenByName("type"); List<Element> types = element.getChildrenByName("type");
Set<String> typeCodes = new HashSet<>(); Set<String> typeCodes = new HashSet<>();
@ -415,7 +415,7 @@ public class StructureDefinitionValidator extends BaseValidator {
tc = tcv.primitiveValue(); tc = tcv.primitiveValue();
} }
} }
if (Utilities.noString(tc) && type.hasChild("code")) { if (Utilities.noString(tc) && type.hasChild("code", false)) {
if (VersionUtilities.isR4Plus(context.getVersion())) { if (VersionUtilities.isR4Plus(context.getVersion())) {
ok = rule(errors, "2023-03-16", IssueType.INVALID, stack.getLiteralPath(), false, I18nConstants.SD_NO_TYPE_CODE_ON_CODE, path, sd.getId()) && ok; ok = rule(errors, "2023-03-16", IssueType.INVALID, stack.getLiteralPath(), false, I18nConstants.SD_NO_TYPE_CODE_ON_CODE, path, sd.getId()) && ok;
} }
@ -449,28 +449,28 @@ public class StructureDefinitionValidator extends BaseValidator {
hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, path); hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, path);
} }
} }
if (element.hasChild("binding")) { if (element.hasChild("binding", false)) {
if (!typeCodes.isEmpty()) { if (!typeCodes.isEmpty()) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok;
} }
Element binding = element.getNamedChild("binding"); Element binding = element.getNamedChild("binding", false);
ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok; ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok;
} else { } else {
// this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back
// String bt = boundType(typeCodes); // String bt = boundType(typeCodes);
// hint(errors, UNKNOWN_DATE_TIME, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt); // hint(errors, UNKNOWN_DATE_TIME, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path", false), bt);
} }
if (!typeCodes.isEmpty()) { if (!typeCodes.isEmpty()) {
if (element.hasChild("maxLength")) { if (element.hasChild("maxLength", false)) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxLength", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxLength", typeCodes) && ok;
} }
if (element.hasExtension(ToolingExtensions.EXT_MIN_LENGTH)) { if (element.hasExtension(ToolingExtensions.EXT_MIN_LENGTH)) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinLength Extension", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinLength Extension", typeCodes) && ok;
} }
if (element.hasChild("minValue")) { if (element.hasChild("minValue", false)) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinValue", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinValue", typeCodes) && ok;
} }
if (element.hasChild("maxValue")) { if (element.hasChild("maxValue", false)) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxValue", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxValue", typeCodes) && ok;
} }
if (element.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) { if (element.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) {
@ -482,15 +482,15 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
// in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type // in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) { if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) {
if (rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) { if (rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference", false), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) {
// if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint // if we see fixed[x] or pattern[x] applied to a repeating element, we'll give the user a hint
boolean repeating = !Utilities.existsInList(element.getChildValue("max"), "0", "1"); boolean repeating = !Utilities.existsInList(element.getChildValue("max"), "0", "1");
Element v = element.getNamedChild("defaultValue"); Element v = element.getNamedChild("defaultValue", false);
if (v != null) { if (v != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "defaultValue", v.fhirType(), typeCodes) && ok;
} }
v = element.getNamedChild("fixed"); v = element.getNamedChild("fixed", false);
if (v != null) { if (v != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes) && ok;
hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed"); hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed");
@ -500,7 +500,7 @@ public class StructureDefinitionValidator extends BaseValidator {
warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), false, I18nConstants.SD_VALUE_COMPLEX_FIXED, v.fhirType()); warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), false, I18nConstants.SD_VALUE_COMPLEX_FIXED, v.fhirType());
} }
} }
v = element.getNamedChild("pattern"); v = element.getNamedChild("pattern", false);
if (v != null) { if (v != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes) && ok;
hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern"); hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern");
@ -516,7 +516,7 @@ public class StructureDefinitionValidator extends BaseValidator {
List<Element> constraints = element.getChildrenByName("constraint"); List<Element> constraints = element.getChildrenByName("constraint");
int cc = 0; int cc = 0;
for (Element invariant : constraints) { for (Element invariant : constraints) {
ok = validateElementDefinitionInvariant(errors, invariant, stack.push(invariant, cc, null, null), invariantMap, elements, element, element.getNamedChildValue("path"), rootPath, profileUrl, profileType, snapshot, base) && ok; ok = validateElementDefinitionInvariant(errors, invariant, stack.push(invariant, cc, null, null), invariantMap, elements, element, element.getNamedChildValue("path", false), rootPath, profileUrl, profileType, snapshot, base) && ok;
cc++; cc++;
} }
return ok; return ok;
@ -525,9 +525,9 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean validateElementDefinitionInvariant(List<ValidationMessage> errors, Element invariant, NodeStack stack, Map<String, String> invariantMap, List<Element> elements, Element element, private boolean validateElementDefinitionInvariant(List<ValidationMessage> errors, Element invariant, NodeStack stack, Map<String, String> invariantMap, List<Element> elements, Element element,
String path, String rootPath, String profileUrl, String profileType, boolean snapshot, StructureDefinition base) { String path, String rootPath, String profileUrl, String profileType, boolean snapshot, StructureDefinition base) {
boolean ok = true; boolean ok = true;
String key = invariant.getNamedChildValue("key"); String key = invariant.getNamedChildValue("key", false);
String expression = invariant.getNamedChildValue("expression"); String expression = invariant.getNamedChildValue("expression", false);
String source = invariant.getNamedChildValue("source"); String source = invariant.getNamedChildValue("source", false);
if (warning(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(key), I18nConstants.ED_INVARIANT_NO_KEY)) { if (warning(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(key), I18nConstants.ED_INVARIANT_NO_KEY)) {
if (hint(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(expression) || VersionUtilities.isR5Plus(context.getVersion()), I18nConstants.ED_INVARIANT_NO_EXPRESSION, key)) { // not for R5 - there's an invariant if (hint(errors, "2023-06-19", IssueType.INFORMATIONAL, stack, !Utilities.noString(expression) || VersionUtilities.isR5Plus(context.getVersion()), I18nConstants.ED_INVARIANT_NO_EXPRESSION, key)) { // not for R5 - there's an invariant
if (snapshot) {// we just don't have enough information to figure out the context in a differential if (snapshot) {// we just don't have enough information to figure out the context in a differential
@ -554,7 +554,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
if (types.size() == 0) { if (types.size() == 0) {
// we got to the root before finding anything typed // we got to the root before finding anything typed
types.add(elements.get(0).getNamedChildValue("path")); types.add(elements.get(0).getNamedChildValue("path", false));
} }
List<IssueMessage> warnings = new ArrayList<>(); List<IssueMessage> warnings = new ArrayList<>();
ValidationContext vc = new ValidationContext(invariant); ValidationContext vc = new ValidationContext(invariant);
@ -619,7 +619,7 @@ public class StructureDefinitionValidator extends BaseValidator {
private Object listContexts(Element sd) { private Object listContexts(Element sd) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Element e : sd.getChildren("context")) { for (Element e : sd.getChildren("context")) {
b.append(e.getNamedChildValue("type")+"="+e.getNamedChildValue("expression")); b.append(e.getNamedChildValue("type", false)+"="+e.getNamedChildValue("expression", false));
} }
return b.toString(); return b.toString();
} }
@ -627,16 +627,16 @@ public class StructureDefinitionValidator extends BaseValidator {
private List<String> listTypeContexts(Element sd) { private List<String> listTypeContexts(Element sd) {
List<String> types = new ArrayList<>(); List<String> types = new ArrayList<>();
for (Element e : sd.getChildren("context")) { for (Element e : sd.getChildren("context")) {
switch (e.getNamedChildValue("type")) { switch (e.getNamedChildValue("type", false)) {
case "fhirpath" : case "fhirpath" :
break; break;
case "element" : case "element" :
types.add(e.getNamedChildValue("expression")); types.add(e.getNamedChildValue("expression", false));
break; break;
case "extension" : case "extension" :
// this isn't defined? // this isn't defined?
types.add(e.getNamedChildValue("Extension")); types.add(e.getNamedChildValue("Extension", false));
types.add(e.getNamedChildValue("Extension.value")); types.add(e.getNamedChildValue("Extension.value", false));
break; break;
default: default:
} }
@ -656,16 +656,16 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
private String tail(Element te, Element newte) { private String tail(Element te, Element newte) {
String p = te.getNamedChildValue("path"); String p = te.getNamedChildValue("path", false);
String pn = newte.getNamedChildValue("path"); String pn = newte.getNamedChildValue("path", false);
return p.substring(pn.length()+1); return p.substring(pn.length()+1);
} }
private Element getParent(List<Element> elements, Element te) { private Element getParent(List<Element> elements, Element te) {
int i = elements.indexOf(te) - 1; int i = elements.indexOf(te) - 1;
String path = te.getNamedChildValue("path"); String path = te.getNamedChildValue("path", false);
while (i >= 0) { while (i >= 0) {
String p = elements.get(i).getNamedChildValue("path"); String p = elements.get(i).getNamedChildValue("path", false);
if (path.startsWith(p+".")) { if (path.startsWith(p+".")) {
return elements.get(i); return elements.get(i);
} }
@ -676,8 +676,8 @@ public class StructureDefinitionValidator extends BaseValidator {
private List<String> getTypesForElement(List<Element> elements, Element element, String profileType) { private List<String> getTypesForElement(List<Element> elements, Element element, String profileType) {
List<String> types = new ArrayList<>(); List<String> types = new ArrayList<>();
if (element.hasChild("path") && !element.getNamedChildValue("path").contains(".")) { if (element.hasChild("path", false) && !element.getNamedChildValue("path", false).contains(".")) {
String t = element.getNamedChildValue("path"); String t = element.getNamedChildValue("path", false);
if (profileType.equals(t)) { if (profileType.equals(t)) {
types.add(profileType); types.add(profileType);
} else if (profileType.endsWith("/"+t)) { } else if (profileType.endsWith("/"+t)) {
@ -687,16 +687,16 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
} else { } else {
for (Element tr : element.getChildrenByName("type")) { for (Element tr : element.getChildrenByName("type")) {
String t = tr.getNamedChildValue("code"); String t = tr.getNamedChildValue("code", false);
if (t.startsWith("http://hl7.org/fhirpath")) { if (t.startsWith("http://hl7.org/fhirpath")) {
t = tr.getExtensionValue("http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type").primitiveValue(); t = tr.getExtensionValue("http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type").primitiveValue();
} }
if (t != null) { if (t != null) {
if (isAbstractType(t) && hasChildren(element, elements) ) { if (isAbstractType(t) && hasChildren(element, elements) ) {
if (!Utilities.isAbsoluteUrl(profileType)) { if (!Utilities.isAbsoluteUrl(profileType)) {
types.add(element.getNamedChildValue("path")); types.add(element.getNamedChildValue("path", false));
} else { } else {
types.add(profileType+"#"+element.getNamedChildValue("path")); types.add(profileType+"#"+element.getNamedChildValue("path", false));
} }
} else { } else {
types.add(t); types.add(t);
@ -709,9 +709,9 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean hasChildren(Element element, List<Element> elements) { private boolean hasChildren(Element element, List<Element> elements) {
int i = elements.indexOf(element); int i = elements.indexOf(element);
String path = element.getNamedChildValue("path")+"."; String path = element.getNamedChildValue("path", false)+".";
while (i < elements.size()) { while (i < elements.size()) {
String p = elements.get(i).getNamedChildValue("path")+"."; String p = elements.get(i).getNamedChildValue("path", false)+".";
if (p.startsWith(path)) { if (p.startsWith(path)) {
return true; return true;
} }
@ -727,7 +727,7 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean meaningWhenMissingAllowed(Element element) { private boolean meaningWhenMissingAllowed(Element element) {
// allowed to use meaningWhenMissing on the root of an element to say what it means when the extension // allowed to use meaningWhenMissing on the root of an element to say what it means when the extension
// is not present. // is not present.
String path = element.getNamedChildValue("path"); String path = element.getNamedChildValue("path", false);
return path != null && ("Extension".equals(path) || (path.endsWith(".extension"))); return path != null && ("Extension".equals(path) || (path.endsWith(".extension")));
} }
@ -866,9 +866,9 @@ public class StructureDefinitionValidator extends BaseValidator {
hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), bindables.size() <= 1, I18nConstants.SD_ED_BIND_MULTIPLE_TYPES, path, typeCodes.toString()); hint(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), bindables.size() <= 1, I18nConstants.SD_ED_BIND_MULTIPLE_TYPES, path, typeCodes.toString());
} }
if (binding.hasChild("valueSet")) { if (binding.hasChild("valueSet", false)) {
Element valueSet = binding.getNamedChild("valueSet"); Element valueSet = binding.getNamedChild("valueSet", false);
String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("reference"); String ref = valueSet.hasPrimitiveValue() ? valueSet.primitiveValue() : valueSet.getNamedChildValue("reference", false);
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) { if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || ref != null, I18nConstants.SD_ED_SHOULD_BIND_WITH_VS, path)) {
Resource vs = context.fetchResource(Resource.class, ref); Resource vs = context.fetchResource(Resource.class, ref);
@ -901,7 +901,7 @@ public class StructureDefinitionValidator extends BaseValidator {
private boolean validateElementType(List<ValidationMessage> errors, Element type, NodeStack stack, StructureDefinition sd, String path, boolean logical) { private boolean validateElementType(List<ValidationMessage> errors, Element type, NodeStack stack, StructureDefinition sd, String path, boolean logical) {
boolean ok = true; boolean ok = true;
String code = type.getNamedChildValue("code"); String code = type.getNamedChildValue("code", false);
if (code == null && path != null) { if (code == null && path != null) {
code = getTypeCodeFromSD(sd, path); code = getTypeCodeFromSD(sd, path);
} else { } else {
@ -1118,8 +1118,8 @@ public class StructureDefinitionValidator extends BaseValidator {
private String getExtensionValue(Element element, String url) { private String getExtensionValue(Element element, String url) {
List<Element> extensions = element.getChildrenByName("extension"); List<Element> extensions = element.getChildrenByName("extension");
for (Element extension : extensions) { for (Element extension : extensions) {
if (url.equals(extension.getNamedChildValue("url"))) { if (url.equals(extension.getNamedChildValue("url", false))) {
return extension.getNamedChildValue("value"); return extension.getNamedChildValue("value", false);
} }
} }
return null; return null;

View File

@ -355,7 +355,7 @@ public class StructureMapValidator extends BaseValidator {
private boolean hasInputTypes(Element group) { private boolean hasInputTypes(Element group) {
List<Element> inputs = group.getChildrenByName("input"); List<Element> inputs = group.getChildrenByName("input");
for (Element input : inputs) { for (Element input : inputs) {
if (!input.hasChild("type")) { if (!input.hasChild("type", false)) {
return false; return false;
} }
} }
@ -385,7 +385,7 @@ public class StructureMapValidator extends BaseValidator {
grpNames.add(name); grpNames.add(name);
} }
Element extend = group.getNamedChild("extends"); Element extend = group.getNamedChild("extends", false);
if (extend != null) { if (extend != null) {
ResolvedGroup grp = resolveGroup(extend.primitiveValue(), src); ResolvedGroup grp = resolveGroup(extend.primitiveValue(), src);
if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, extend.primitiveValue())) { if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, extend.primitiveValue())) {
@ -774,14 +774,14 @@ public class StructureMapValidator extends BaseValidator {
break; break;
case "cc" : case "cc" :
ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 2 || params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 2 || params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
ok = checkParamExistsOrPrimitive(errors, params.size() > 0 ? params.get(0).getNamedChild("value") : null, "cc", "system", target, variables, stack, ok, true); ok = checkParamExistsOrPrimitive(errors, params.size() > 0 ? params.get(0).getNamedChild("value", false) : null, "cc", "system", target, variables, stack, ok, true);
ok = checkParamExistsOrPrimitive(errors, params.size() > 1 ? params.get(1).getNamedChild("value") : null, "cc", "code", target, variables, stack, ok, true); ok = checkParamExistsOrPrimitive(errors, params.size() > 1 ? params.get(1).getNamedChild("value", false) : null, "cc", "code", target, variables, stack, ok, true);
ok = checkParamExistsOrPrimitive(errors, params.size() > 2 ? params.get(2).getNamedChild("value") : null, "cc", "display", target, variables, stack, ok, false); ok = checkParamExistsOrPrimitive(errors, params.size() > 2 ? params.get(2).getNamedChild("value", false) : null, "cc", "display", target, variables, stack, ok, false);
break; break;
case "append" : case "append" :
ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() > 0, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() > 0, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
for (int i = 0; i < params.size(); i++) { for (int i = 0; i < params.size(); i++) {
ok = checkParamExistsOrPrimitive(errors, params.get(1).getNamedChild("value"), "cc", "parameter "+i, target, variables, stack, ok, false); ok = checkParamExistsOrPrimitive(errors, params.get(1).getNamedChild("value", false), "cc", "parameter "+i, target, variables, stack, ok, false);
} }
break; break;
case "uuid" : case "uuid" :
@ -789,9 +789,9 @@ public class StructureMapValidator extends BaseValidator {
break; break;
case "translate": case "translate":
ok = rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok; ok = rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
Element srcE = params.size() > 0 ? params.get(0).getNamedChild("value") : null; Element srcE = params.size() > 0 ? params.get(0).getNamedChild("value", false) : null;
Element mapE = params.size() > 1? params.get(1).getNamedChild("value") : null; Element mapE = params.size() > 1? params.get(1).getNamedChild("value", false) : null;
Element modeE = params.size() > 2 ? params.get(2).getNamedChild("value") : null; Element modeE = params.size() > 2 ? params.get(2).getNamedChild("value", false) : null;
VariableDefn sv = null; VariableDefn sv = null;
// srcE - if it's an id, the variable must exist // srcE - if it's an id, the variable must exist
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), srcE != null, I18nConstants.SM_TARGET_TRANSFORM_TRANSLATE_NO_PARAM, "source")) { if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), srcE != null, I18nConstants.SM_TARGET_TRANSFORM_TRANSLATE_NO_PARAM, "source")) {
@ -1205,7 +1205,7 @@ public class StructureMapValidator extends BaseValidator {
List<Element> structures = map.getChildrenByName("structure"); List<Element> structures = map.getChildrenByName("structure");
for (Element structure : structures) { for (Element structure : structures) {
String alias = structure.getChildValue("alias"); String alias = structure.getChildValue("alias");
if ((alias != null && alias.equals(type)) && (mode == null || mode.equals(structure.getNamedChildValue("mode")))) { if ((alias != null && alias.equals(type)) && (mode == null || mode.equals(structure.getNamedChildValue("mode", false)))) {
return structure.getChildValue("url"); return structure.getChildValue("url");
} }
} }
@ -1301,7 +1301,7 @@ public class StructureMapValidator extends BaseValidator {
private VariableDefn getParameter(List<ValidationMessage> errors, Element param, NodeStack pstack, VariableSet variables, StructureMapInputMode mode) { private VariableDefn getParameter(List<ValidationMessage> errors, Element param, NodeStack pstack, VariableSet variables, StructureMapInputMode mode) {
if (VersionUtilities.isR5Plus(context.getVersion())) { if (VersionUtilities.isR5Plus(context.getVersion())) {
Element v = param.getNamedChild("value"); Element v = param.getNamedChild("value", false);
if (v.fhirType().equals("id")) { if (v.fhirType().equals("id")) {
return variables.getVariable(v.primitiveValue(), mode == StructureMapInputMode.SOURCE); return variables.getVariable(v.primitiveValue(), mode == StructureMapInputMode.SOURCE);
} else { } else {

View File

@ -62,7 +62,7 @@ public class ValueSetValidator extends BaseValidator {
List<Element> composes = vs.getChildrenByName("compose"); List<Element> composes = vs.getChildrenByName("compose");
int cc = 0; int cc = 0;
for (Element compose : composes) { for (Element compose : composes) {
ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok; ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url", false), "retired".equals(vs.getNamedChildValue("url", false))) & ok;
cc++; cc++;
} }
} }
@ -76,22 +76,22 @@ public class ValueSetValidator extends BaseValidator {
if (parent.isForPublication()) { if (parent.isForPublication()) {
if (isHL7(vs)) { if (isHL7(vs)) {
boolean ok = true; boolean ok = true;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "url") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "url") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "version") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "version") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "title") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "title") && ok;
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name"), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING_HL7, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name", false), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING_HL7, "name");
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "status") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "status") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "experimental") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "experimental") && ok;
ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description"), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "description") && ok; ok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description", false), I18nConstants.VALUESET_SHAREABLE_MISSING_HL7, "description") && ok;
return ok; return ok;
} else { } else {
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url"), I18nConstants.VALUESET_SHAREABLE_MISSING, "url"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("url", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "url");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version"), I18nConstants.VALUESET_SHAREABLE_MISSING, "version"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("version", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "version");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title"), I18nConstants.VALUESET_SHAREABLE_MISSING, "title"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("title", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "title");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name"), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING, "name"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("name", false), I18nConstants.VALUESET_SHAREABLE_EXTRA_MISSING, "name");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status"), I18nConstants.VALUESET_SHAREABLE_MISSING, "status"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("status", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "status");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental"), I18nConstants.VALUESET_SHAREABLE_MISSING, "experimental"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("experimental", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "experimental");
warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description"), I18nConstants.VALUESET_SHAREABLE_MISSING, "description"); warning(errors, NO_RULE_DATE, IssueType.REQUIRED, vs.line(), vs.col(), stack.getLiteralPath(), vs.hasChild("description", false), I18nConstants.VALUESET_SHAREABLE_MISSING, "description");
} }
} }
return true; return true;

View File

@ -395,7 +395,7 @@ public class EnableWhenEvaluator {
} }
private boolean hasLinkId(Element item, String linkId) { private boolean hasLinkId(Element item, String linkId) {
Element linkIdChild = item.getNamedChild(LINKID_ELEMENT); Element linkIdChild = item.getNamedChild(LINKID_ELEMENT, false);
if (linkIdChild != null && linkIdChild.getValue().equals(linkId)) { if (linkIdChild != null && linkIdChild.getValue().equals(linkId)) {
return true; return true;
} }

View File

@ -245,5 +245,4 @@ public class NodeStack {
return element.col(); return element.col();
} }
} }

View File

@ -122,7 +122,7 @@ public class IPAValidator {
List<Element> entries = bundle.getChildren("entry"); List<Element> entries = bundle.getChildren("entry");
int i = 0; int i = 0;
for (Element entry : entries) { for (Element entry : entries) {
Element resource = entry.getNamedChild("resource"); Element resource = entry.getNamedChild("resource", false);
if (resource != null && resource.fhirType().equals("Patient")) { if (resource != null && resource.fhirType().equals("Patient")) {
validator.validate(this, vn.getIssues(), "Bundle.entry["+i+"].resource", resource, "http://hl7.org/fhir/uv/ipa/StructureDefinition/ipa-patient"); validator.validate(this, vn.getIssues(), "Bundle.entry["+i+"].resource", resource, "http://hl7.org/fhir/uv/ipa/StructureDefinition/ipa-patient");
list.add(resource); list.add(resource);
@ -145,8 +145,8 @@ public class IPAValidator {
// we check that there's a self link // we check that there's a self link
Element sl = null; Element sl = null;
for (Element e : bundle.getChildren("link")) { for (Element e : bundle.getChildren("link")) {
if ("self".equals(e.getNamedChildValue("relation"))) { if ("self".equals(e.getNamedChildValue("relation", false))) {
sl = e.getNamedChild("url"); sl = e.getNamedChild("url", false);
} }
} }
if (sl == null) { if (sl == null) {

View File

@ -115,7 +115,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
private static final boolean BUILD_NEW = true; private static final boolean BUILD_NEW = true;
private static final boolean CLONE = true; private static final boolean CLONE = true;
@Parameters(name = "{index}: id {0}") @Parameters(name = "{0} (#{index})")
public static Iterable<Object[]> data() throws IOException { public static Iterable<Object[]> data() throws IOException {
String contents = TestingUtilities.loadTestResource("validator", "manifest.json"); String contents = TestingUtilities.loadTestResource("validator", "manifest.json");