Fix up path management in the validator for resolving references in Bundles
This commit is contained in:
parent
a939e14db9
commit
0038e3a57b
|
@ -165,6 +165,10 @@ public class JsonParser extends ParserBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Element parse(List<ValidationMessage> errors, JsonObject object) throws FHIRException {
|
public Element parse(List<ValidationMessage> errors, JsonObject object) throws FHIRException {
|
||||||
|
return parse(errors, object, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element parse(List<ValidationMessage> errors, JsonObject object, String statedPath) throws FHIRException {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
System.out.println("What?");
|
System.out.println("What?");
|
||||||
}
|
}
|
||||||
|
@ -187,16 +191,16 @@ public class JsonParser extends ParserBase {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path = name;
|
path = statedPath == null ? name : statedPath;
|
||||||
} else {
|
} else {
|
||||||
name = sd.getType();
|
name = sd.getType();
|
||||||
path = sd.getTypeTail();
|
path = statedPath == null ? sd.getTypeTail() : statedPath;
|
||||||
}
|
}
|
||||||
baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.getProfileUtilities(), this.getContextUtilities())).setFormat(FhirFormat.JSON);
|
baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.getProfileUtilities(), this.getContextUtilities())).setFormat(FhirFormat.JSON);
|
||||||
checkObject(errors, object, baseElement, path);
|
checkObject(errors, object, baseElement, path);
|
||||||
baseElement.markLocation(line(object), col(object));
|
baseElement.markLocation(line(object), col(object));
|
||||||
baseElement.setType(name);
|
baseElement.setType(name);
|
||||||
baseElement.setPath(baseElement.fhirTypeRoot());
|
baseElement.setPath(statedPath == null ? baseElement.fhirTypeRoot() : statedPath);
|
||||||
parseChildren(errors, path, object, baseElement, true, null);
|
parseChildren(errors, path, object, baseElement, true, null);
|
||||||
baseElement.numberChildren();
|
baseElement.numberChildren();
|
||||||
return baseElement;
|
return baseElement;
|
||||||
|
|
|
@ -167,7 +167,7 @@ public class SHCParser extends ParserBase {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// ok. all checks passed, we can now validate the bundle
|
// ok. all checks passed, we can now validate the bundle
|
||||||
bnd.setElement(jsonParser.parse(bnd.getErrors(), cs.getJsonObject("fhirBundle")));
|
bnd.setElement(jsonParser.parse(bnd.getErrors(), cs.getJsonObject("fhirBundle"), path));
|
||||||
bnd.setElementPath(path);
|
bnd.setElementPath(path);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -992,7 +992,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
setParents(element);
|
setParents(element);
|
||||||
|
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
NodeStack stack = new NodeStack(context, path, element, validationLanguage);
|
NodeStack stack = new NodeStack(context, null, element, validationLanguage);
|
||||||
if (profiles == null || profiles.isEmpty()) {
|
if (profiles == null || profiles.isEmpty()) {
|
||||||
validateResource(new ValidationContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition), false, false);
|
validateResource(new ValidationContext(appContext, element), errors, element, element, null, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.BaseDefinition), false, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4695,18 +4695,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
} else {
|
} else {
|
||||||
// work back through the parent list - if any of them are bundles, try to resolve
|
// work back through the parent list - if any of them are bundles, try to resolve
|
||||||
// the resource in the bundle
|
// the resource in the bundle
|
||||||
|
|
||||||
|
// 2024-04-05 - must work through the element parents not the stack parents, as the stack is not necessarily reflective of the full parent list
|
||||||
|
Element focus = stack.getElement();
|
||||||
String fullUrl = null; // we're going to try to work this out as we go up
|
String fullUrl = null; // we're going to try to work this out as we go up
|
||||||
while (stack != null && stack.getElement() != null) {
|
while (focus != null) {
|
||||||
if (stack.getElement().getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && stack.getParent() != null && stack.getParent().getElement().getName().equals(ENTRY)) {
|
// track the stack while we can
|
||||||
String type = stack.getParent().getParent().getElement().getChildValue(TYPE);
|
if (focus.getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && focus != null && focus.getParentForValidator().getName().equals(ENTRY)) {
|
||||||
fullUrl = stack.getParent().getElement().getChildValue(FULL_URL); // we don't try to resolve contained references across this boundary
|
String type = focus.getParentForValidator().getChildValue(TYPE);
|
||||||
|
fullUrl = focus.getParentForValidator().getChildValue(FULL_URL); // we don't try to resolve contained references across this boundary
|
||||||
if (fullUrl == null)
|
if (fullUrl == null)
|
||||||
bh.see(rule(errors, NO_RULE_DATE, IssueType.REQUIRED, stack.getParent().getElement().line(), stack.getParent().getElement().col(), stack.getParent().getLiteralPath(),
|
bh.see(rule(errors, NO_RULE_DATE, IssueType.REQUIRED, focus.getParentForValidator().line(), focus.getParentForValidator().col(), focus.getParentForValidator().getPath(),
|
||||||
Utilities.existsInList(type, "batch-response", "transaction-response") || fullUrl != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFULLURL));
|
Utilities.existsInList(type, "batch-response", "transaction-response") || fullUrl != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOFULLURL));
|
||||||
}
|
}
|
||||||
if (BUNDLE.equals(stack.getElement().getType())) {
|
if (BUNDLE.equals(focus.getType())) {
|
||||||
String type = stack.getElement().getChildValue(TYPE);
|
String type = focus.getChildValue(TYPE);
|
||||||
IndexedElement res = getFromBundle(stack.getElement(), ref, fullUrl, errors, path, type, "transaction".equals(type), bh);
|
IndexedElement res = getFromBundle(focus, ref, fullUrl, errors, path, type, "transaction".equals(type), bh);
|
||||||
if (res == null) {
|
if (res == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4714,15 +4718,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
rr.setResource(res.getMatch());
|
rr.setResource(res.getMatch());
|
||||||
rr.setFocus(res.getMatch());
|
rr.setFocus(res.getMatch());
|
||||||
rr.setExternal(false);
|
rr.setExternal(false);
|
||||||
rr.setStack(stack.push(res.getEntry(), res.getIndex(), res.getEntry().getProperty().getDefinition(),
|
rr.setStack(new NodeStack(context, null, res.getMatch(), validationLanguage));
|
||||||
res.getEntry().getProperty().getDefinition()).push(res.getMatch(), -1,
|
rr.setVia(stack);
|
||||||
res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
|
//
|
||||||
|
// !stack.push(res.getEntry(), res.getIndex(), res.getEntry().getProperty().getDefinition(),
|
||||||
|
// res.getEntry().getProperty().getDefinition()).push(res.getMatch(), -1,
|
||||||
|
// res.getMatch().getProperty().getDefinition(), res.getMatch().getProperty().getDefinition()));
|
||||||
rr.getStack().pathComment(rr.getResource().fhirType()+"/"+rr.getResource().getIdBase());
|
rr.getStack().pathComment(rr.getResource().fhirType()+"/"+rr.getResource().getIdBase());
|
||||||
return rr;
|
return rr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stack.getElement().getSpecial() == SpecialElement.PARAMETER && stack.getParent() != null) {
|
if (focus.getSpecial() == SpecialElement.PARAMETER && focus.getParentForValidator() != null) {
|
||||||
NodeStack tgt = findInParams(stack.getParent().getParent(), ref);
|
NodeStack tgt = findInParams(focus.getParentForValidator().getParentForValidator(), ref, stack);
|
||||||
if (tgt != null) {
|
if (tgt != null) {
|
||||||
ResolvedReference rr = new ResolvedReference();
|
ResolvedReference rr = new ResolvedReference();
|
||||||
rr.setResource(tgt.getElement());
|
rr.setResource(tgt.getElement());
|
||||||
|
@ -4733,7 +4740,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return rr;
|
return rr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack = stack.getParent();
|
focus = focus.getParentForValidator();
|
||||||
}
|
}
|
||||||
// we can get here if we got called via FHIRPath conformsTo which breaks the stack continuity.
|
// we can get here if we got called via FHIRPath conformsTo which breaks the stack continuity.
|
||||||
if (groupingResource != null && BUNDLE.equals(groupingResource.fhirType())) { // it could also be a Parameters resource - that case isn't handled yet
|
if (groupingResource != null && BUNDLE.equals(groupingResource.fhirType())) { // it could also be a Parameters resource - that case isn't handled yet
|
||||||
|
@ -4759,10 +4766,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeStack findInParams(NodeStack params, String ref) {
|
private NodeStack findInParams(Element params, String ref, NodeStack stack) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Element child : params.getElement().getChildren("parameter")) {
|
for (Element child : params.getChildren("parameter")) {
|
||||||
NodeStack p = params.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition());
|
NodeStack p = stack.push(child, i, child.getProperty().getDefinition(), child.getProperty().getDefinition());
|
||||||
if (child.hasChild("resource", false)) {
|
if (child.hasChild("resource", false)) {
|
||||||
Element res = child.getNamedChild("resource", false);
|
Element res = child.getNamedChild("resource", false);
|
||||||
if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) {
|
if ((res.fhirType()+"/"+res.getIdBase()).equals(ref)) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class NodeStack {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
ids = new HashMap<>();
|
ids = new HashMap<>();
|
||||||
this.element = element;
|
this.element = element;
|
||||||
literalPath = (initialPath == null ? "" : initialPath+".") + element.getPath();
|
literalPath = (initialPath == null ? "" : initialPath+".") + buildPathForElement(element, true);
|
||||||
workingLang = validationLanguage;
|
workingLang = validationLanguage;
|
||||||
if (!element.getName().equals(element.fhirType())) {
|
if (!element.getName().equals(element.fhirType())) {
|
||||||
logicalPaths = new HashSet<>();
|
logicalPaths = new HashSet<>();
|
||||||
|
@ -45,6 +45,21 @@ public class NodeStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String buildPathForElement(Element e, boolean first) {
|
||||||
|
if (e.getParentForValidator() != null) {
|
||||||
|
String node = e.getName().contains("/") ? e.getName().substring(e.getName().lastIndexOf("/")+1) : e.getName();
|
||||||
|
if (e.hasIndex() && e.getProperty().isList() && e.getSpecial() == null) {
|
||||||
|
node = node+"["+Integer.toString(e.getIndex())+"]";
|
||||||
|
}
|
||||||
|
if (!first && e.isResource()) {
|
||||||
|
node = node +"/*"+e.fhirType()+"/"+e.getIdBase()+"*/";
|
||||||
|
}
|
||||||
|
return buildPathForElement(e.getParentForValidator(), false)+"."+node;
|
||||||
|
} else {
|
||||||
|
return e.getPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public NodeStack(IWorkerContext context, Element element, String refPath, String validationLanguage) {
|
public NodeStack(IWorkerContext context, Element element, String refPath, String validationLanguage) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
ids = new HashMap<>();
|
ids = new HashMap<>();
|
||||||
|
|
|
@ -9,6 +9,7 @@ public class ResolvedReference {
|
||||||
private Element focus;
|
private Element focus;
|
||||||
private boolean external;
|
private boolean external;
|
||||||
private NodeStack stack;
|
private NodeStack stack;
|
||||||
|
private NodeStack via;
|
||||||
|
|
||||||
public ResolvedReference setResource(Element resource) {
|
public ResolvedReference setResource(Element resource) {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
|
@ -50,6 +51,14 @@ public class ResolvedReference {
|
||||||
return focus;
|
return focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NodeStack getVia() {
|
||||||
|
return via;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVia(NodeStack via) {
|
||||||
|
this.via = via;
|
||||||
|
}
|
||||||
|
|
||||||
public ValidationContext valContext(ValidationContext valContext, StructureDefinition profile) {
|
public ValidationContext valContext(ValidationContext valContext, StructureDefinition profile) {
|
||||||
if (external) {
|
if (external) {
|
||||||
return valContext.forRemoteReference(profile, resource);
|
return valContext.forRemoteReference(profile, resource);
|
||||||
|
|
Loading…
Reference in New Issue