fix ref-1 constraint (define %rootResource)

This commit is contained in:
Grahame Grieve 2019-08-08 21:03:27 +10:00
parent bd8cfed092
commit 7ef320b6bb
12 changed files with 117 additions and 81 deletions

View File

@ -486,7 +486,7 @@ public class FHIRPathEngine {
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -504,7 +504,7 @@ public class FHIRPathEngine {
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(null, base.isResource() ? base : null, base, null, base), list, exp, true); return execute(new ExecutionContext(null, base.isResource() ? base : null, base.isResource() ? base : null, base, null, base), list, exp, true);
} }
/** /**
@ -516,12 +516,12 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Resource resource, Base base, ExpressionNode ExpressionNode) throws FHIRException { public List<Base> evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, ExpressionNode ExpressionNode) throws FHIRException {
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -533,12 +533,12 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Base resource, Base base, ExpressionNode ExpressionNode) throws FHIRException { public List<Base> evaluate(Object appContext, Base focusResource, Base rootResource, Base base, ExpressionNode ExpressionNode) throws FHIRException {
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -550,13 +550,13 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Resource resource, Base base, String path) throws FHIRException { public List<Base> evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, String path) throws FHIRException {
ExpressionNode exp = parse(path); ExpressionNode exp = parse(path);
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, exp, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, exp, true);
} }
/** /**
@ -568,8 +568,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Resource resource, Base base, String path) throws FHIRException { public boolean evaluateToBoolean(Resource focusResource, Resource rootResource, Base base, String path) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, path)); return convertToBoolean(evaluate(null, focusResource, rootResource, base, path));
} }
/** /**
@ -580,8 +580,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Resource resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Resource focusResource, Resource rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, node)); return convertToBoolean(evaluate(null, focusResource, rootResource, base, node));
} }
/** /**
@ -593,8 +593,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Object appInfo, Base resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Object appInfo, Resource focusResource, Resource rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(appInfo, resource, base, node)); return convertToBoolean(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -605,8 +605,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Base resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Object appInfo, Base focusResource, Base rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, node)); return convertToBoolean(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -622,8 +622,8 @@ public class FHIRPathEngine {
return convertToString(evaluate(base, path)); return convertToString(evaluate(base, path));
} }
public String evaluateToString(Object appInfo, Base resource, Base base, ExpressionNode node) throws FHIRException { public String evaluateToString(Object appInfo, Base focusResource, Base rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToString(evaluate(appInfo, resource, base, node)); return convertToString(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -705,21 +705,26 @@ public class FHIRPathEngine {
private class ExecutionContext { private class ExecutionContext {
private Object appInfo; private Object appInfo;
private Base resource; private Base focusResource;
private Base rootResource;
private Base context; private Base context;
private Base thisItem; private Base thisItem;
private List<Base> total; private List<Base> total;
private Map<String, Base> aliases; private Map<String, Base> aliases;
public ExecutionContext(Object appInfo, Base resource, Base context, Map<String, Base> aliases, Base thisItem) { public ExecutionContext(Object appInfo, Base resource, Base rootResource, Base context, Map<String, Base> aliases, Base thisItem) {
this.appInfo = appInfo; this.appInfo = appInfo;
this.context = context; this.context = context;
this.resource = resource; this.focusResource = resource;
this.rootResource = rootResource;
this.aliases = aliases; this.aliases = aliases;
this.thisItem = thisItem; this.thisItem = thisItem;
} }
public Base getResource() { public Base getFocusResource() {
return resource; return focusResource;
}
public Base getRootResource() {
return rootResource;
} }
public Base getThisItem() { public Base getThisItem() {
return thisItem; return thisItem;
@ -1307,9 +1312,13 @@ public class FHIRPathEngine {
else if (s.equals("%ucum")) else if (s.equals("%ucum"))
return new StringType("http://unitsofmeasure.org").noExtensions(); return new StringType("http://unitsofmeasure.org").noExtensions();
else if (s.equals("%resource")) { else if (s.equals("%resource")) {
if (context.resource == null) if (context.focusResource == null)
throw new PathEngineException("Cannot use %resource in this context"); throw new PathEngineException("Cannot use %resource in this context");
return context.resource; return context.focusResource;
} else if (s.equals("%rootResource")) {
if (context.rootResource == null)
throw new PathEngineException("Cannot use %rootResource in this context");
return context.rootResource;
} else if (s.equals("%context")) { } else if (s.equals("%context")) {
return context.context; return context.context;
} else if (s.equals("%us-zip")) } else if (s.equals("%us-zip"))
@ -2275,6 +2284,10 @@ public class FHIRPathEngine {
if (context.resource == null) if (context.resource == null)
throw new PathEngineException("%resource cannot be used in this context"); throw new PathEngineException("%resource cannot be used in this context");
return new TypeDetails(CollectionStatus.SINGLETON, context.resource); return new TypeDetails(CollectionStatus.SINGLETON, context.resource);
} else if (s.equals("%rootResource")) {
if (context.resource == null)
throw new PathEngineException("%rootResource cannot be used in this context");
return new TypeDetails(CollectionStatus.SINGLETON, context.resource);
} else if (s.equals("%context")) { } else if (s.equals("%context")) {
return context.context; return context.context;
} else if (s.equals("%map-codes")) } else if (s.equals("%map-codes"))
@ -2809,7 +2822,7 @@ public class FHIRPathEngine {
private ExecutionContext changeThis(ExecutionContext context, Base newThis) { private ExecutionContext changeThis(ExecutionContext context, Base newThis) {
return new ExecutionContext(context.appInfo, context.resource, context.context, context.aliases, newThis); return new ExecutionContext(context.appInfo, context.focusResource, context.rootResource, context.context, context.aliases, newThis);
} }
private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) { private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) {
@ -3281,7 +3294,7 @@ public class FHIRPathEngine {
if (s != null) { if (s != null) {
Base res = null; Base res = null;
if (s.startsWith("#")) { if (s.startsWith("#")) {
Property p = context.resource.getChildByName("contained"); Property p = context.rootResource.getChildByName("contained");
for (Base c : p.getValues()) { for (Base c : p.getValues()) {
if (chompHash(s).equals(chompHash(c.getIdBase()))) { if (chompHash(s).equals(chompHash(c.getIdBase()))) {
res = c; res = c;

View File

@ -489,7 +489,7 @@ public class GraphQLEngine {
if (expression == magicExpression) if (expression == magicExpression)
ss = suffix+'.'+Integer.toString(index); ss = suffix+'.'+Integer.toString(index);
else else
ss = suffix+'.'+fpe.evaluateToString(null, null, value, expression); ss = suffix+'.'+fpe.evaluateToString(null, null, null, value, expression);
if (!sel.getField().hasDirective("flatten")) if (!sel.getField().hasDirective("flatten"))
arg = target.addField(sel.getField().getAlias()+suffix, listStatus(sel.getField(), prop.isList() || inheritedList)); arg = target.addField(sel.getField().getAlias()+suffix, listStatus(sel.getField(), prop.isList() || inheritedList));
} }

View File

@ -125,7 +125,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(statement); compiled = engine.parse(statement);
b.append(engine.evaluateToString(ctxt, resource, resource, compiled)); b.append(engine.evaluateToString(ctxt, resource, resource, resource, compiled));
} }
} }
@ -139,7 +139,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(condition); compiled = engine.parse(condition);
boolean ok = engine.evaluateToBoolean(ctxt, resource, resource, compiled); boolean ok = engine.evaluateToBoolean(ctxt, resource, resource, resource, compiled);
List<LiquidNode> list = ok ? thenBody : elseBody; List<LiquidNode> list = ok ? thenBody : elseBody;
for (LiquidNode n : list) { for (LiquidNode n : list) {
n.evaluate(b, resource, ctxt); n.evaluate(b, resource, ctxt);
@ -156,7 +156,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(condition); compiled = engine.parse(condition);
List<Base> list = engine.evaluate(ctxt, resource, resource, compiled); List<Base> list = engine.evaluate(ctxt, resource, resource, resource, compiled);
LiquidEngineContext lctxt = new LiquidEngineContext(ctxt); LiquidEngineContext lctxt = new LiquidEngineContext(ctxt);
for (Base o : list) { for (Base o : list) {
lctxt.vars.put(varName, o); lctxt.vars.put(varName, o);
@ -180,7 +180,7 @@ public class LiquidEngine implements IEvaluationContext {
Tuple incl = new Tuple(); Tuple incl = new Tuple();
nctxt.vars.put("include", incl); nctxt.vars.put("include", incl);
for (String s : params.keySet()) { for (String s : params.keySet()) {
incl.addProperty(s, engine.evaluate(ctxt, resource, resource, params.get(s))); incl.addProperty(s, engine.evaluate(ctxt, resource, resource, resource, params.get(s)));
} }
for (LiquidNode n : doc.body) { for (LiquidNode n : doc.body) {
n.evaluate(b, resource, nctxt); n.evaluate(b, resource, nctxt);

View File

@ -1682,7 +1682,7 @@ public class StructureMapUtilities {
expr = fpe.parse(src.getElement()); expr = fpe.parse(src.getElement());
src.setUserData(MAP_SEARCH_EXPRESSION, expr); src.setUserData(MAP_SEARCH_EXPRESSION, expr);
} }
String search = fpe.evaluateToString(vars, null, new StringType(), expr); // string is a holder of nothing to ensure that variables are processed correctly String search = fpe.evaluateToString(vars, null, null, new StringType(), expr); // string is a holder of nothing to ensure that variables are processed correctly
items = services.performSearch(context.appInfo, search); items = services.performSearch(context.appInfo, search);
} else { } else {
items = new ArrayList<Base>(); items = new ArrayList<Base>();
@ -1718,7 +1718,7 @@ public class StructureMapUtilities {
} }
List<Base> remove = new ArrayList<Base>(); List<Base> remove = new ArrayList<Base>();
for (Base item : items) { for (Base item : items) {
if (!fpe.evaluateToBoolean(vars, null, item, expr)) { if (!fpe.evaluateToBoolean(vars, null, null, item, expr)) {
log(indent+" condition ["+src.getCondition()+"] for "+item.toString()+" : false"); log(indent+" condition ["+src.getCondition()+"] for "+item.toString()+" : false");
remove.add(item); remove.add(item);
} else } else
@ -1736,7 +1736,7 @@ public class StructureMapUtilities {
} }
List<Base> remove = new ArrayList<Base>(); List<Base> remove = new ArrayList<Base>();
for (Base item : items) { for (Base item : items) {
if (!fpe.evaluateToBoolean(vars, null, item, expr)) if (!fpe.evaluateToBoolean(vars, null, null, item, expr))
throw new FHIRException("Rule \""+ruleId+"\": Check condition failed"); throw new FHIRException("Rule \""+ruleId+"\": Check condition failed");
} }
} }
@ -1750,7 +1750,7 @@ public class StructureMapUtilities {
} }
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Base item : items) for (Base item : items)
b.appendIfNotNull(fpe.evaluateToString(vars, null, item, expr)); b.appendIfNotNull(fpe.evaluateToString(vars, null, null, item, expr));
if (b.length() > 0) if (b.length() > 0)
services.log(b.toString()); services.log(b.toString());
} }
@ -1870,7 +1870,7 @@ public class StructureMapUtilities {
expr = fpe.parse(getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString())); expr = fpe.parse(getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString()));
tgt.setUserData(MAP_WHERE_EXPRESSION, expr); tgt.setUserData(MAP_WHERE_EXPRESSION, expr);
} }
List<Base> v = fpe.evaluate(vars, null, tgt.getParameter().size() == 2 ? getParam(vars, tgt.getParameter().get(0)) : new BooleanType(false), expr); List<Base> v = fpe.evaluate(vars, null, null, tgt.getParameter().size() == 2 ? getParam(vars, tgt.getParameter().get(0)) : new BooleanType(false), expr);
if (v.size() == 0) if (v.size() == 0)
return null; return null;
else if (v.size() != 1) else if (v.size() != 1)

View File

@ -334,6 +334,7 @@ public class SnapShotGenerationTests {
TestScript.AssertionResponseTypes lastOpOutcome = null; TestScript.AssertionResponseTypes lastOpOutcome = null;
for (int i = 0; i < test.getAction().size(); i++) { for (int i = 0; i < test.getAction().size(); i++) {
TestActionComponent action = test.getAction().get(i); TestActionComponent action = test.getAction().get(i);
StructureDefinition sdn = new StructureDefinition();
if (action.hasOperation()) { if (action.hasOperation()) {
lastOpOutcome = AssertionResponseTypes.OKAY; lastOpOutcome = AssertionResponseTypes.OKAY;
try { try {
@ -383,7 +384,7 @@ public class SnapShotGenerationTests {
if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD)) if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))
Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription()); Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription());
else { else {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression()); boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, a.getExpression());
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok); Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
} }
} else { } else {
@ -405,7 +406,7 @@ public class SnapShotGenerationTests {
Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome); Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome);
} }
if (a.hasExpression()) { if (a.hasExpression()) {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression()); boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, a.getExpression());
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok); Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
} }
} }

View File

@ -491,7 +491,7 @@ public class FHIRPathEngine {
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(null, base != null && base.isResource() ? base : null, base != null && base.isResource() ? base : null, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -509,7 +509,7 @@ public class FHIRPathEngine {
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(null, base.isResource() ? base : null, base, null, base), list, exp, true); return execute(new ExecutionContext(null, base.isResource() ? base : null, base.isResource() ? base : null, base, null, base), list, exp, true);
} }
/** /**
@ -521,12 +521,12 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Resource resource, Base base, ExpressionNode ExpressionNode) throws FHIRException { public List<Base> evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, ExpressionNode ExpressionNode) throws FHIRException {
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -538,12 +538,12 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Base resource, Base base, ExpressionNode ExpressionNode) throws FHIRException { public List<Base> evaluate(Object appContext, Base focusResource, Base rootResource, Base base, ExpressionNode ExpressionNode) throws FHIRException {
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, ExpressionNode, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, ExpressionNode, true);
} }
/** /**
@ -555,13 +555,13 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public List<Base> evaluate(Object appContext, Resource resource, Base base, String path) throws FHIRException { public List<Base> evaluate(Object appContext, Resource focusResource, Resource rootResource, Base base, String path) throws FHIRException {
ExpressionNode exp = parse(path); ExpressionNode exp = parse(path);
List<Base> list = new ArrayList<Base>(); List<Base> list = new ArrayList<Base>();
if (base != null) if (base != null)
list.add(base); list.add(base);
log = new StringBuilder(); log = new StringBuilder();
return execute(new ExecutionContext(appContext, resource, base, null, base), list, exp, true); return execute(new ExecutionContext(appContext, focusResource, rootResource, base, null, base), list, exp, true);
} }
/** /**
@ -573,8 +573,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Resource resource, Base base, String path) throws FHIRException { public boolean evaluateToBoolean(Resource focusResource, Resource rootResource, Base base, String path) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, path)); return convertToBoolean(evaluate(null, focusResource, rootResource, base, path));
} }
/** /**
@ -585,8 +585,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Resource resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Resource focusResource, Resource rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, node)); return convertToBoolean(evaluate(null, focusResource, rootResource, base, node));
} }
/** /**
@ -598,8 +598,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Object appInfo, Base resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Object appInfo, Resource focusResource, Resource rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(appInfo, resource, base, node)); return convertToBoolean(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -610,8 +610,8 @@ public class FHIRPathEngine {
* @throws FHIRException * @throws FHIRException
* @ * @
*/ */
public boolean evaluateToBoolean(Base resource, Base base, ExpressionNode node) throws FHIRException { public boolean evaluateToBoolean(Object appInfo, Base focusResource, Base rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToBoolean(evaluate(null, resource, base, node)); return convertToBoolean(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -627,8 +627,8 @@ public class FHIRPathEngine {
return convertToString(evaluate(base, path)); return convertToString(evaluate(base, path));
} }
public String evaluateToString(Object appInfo, Base resource, Base base, ExpressionNode node) throws FHIRException { public String evaluateToString(Object appInfo, Base focusResource, Base rootResource, Base base, ExpressionNode node) throws FHIRException {
return convertToString(evaluate(appInfo, resource, base, node)); return convertToString(evaluate(appInfo, focusResource, rootResource, base, node));
} }
/** /**
@ -710,21 +710,26 @@ public class FHIRPathEngine {
private class ExecutionContext { private class ExecutionContext {
private Object appInfo; private Object appInfo;
private Base resource; private Base focusResource;
private Base rootResource;
private Base context; private Base context;
private Base thisItem; private Base thisItem;
private List<Base> total; private List<Base> total;
private Map<String, Base> aliases; private Map<String, Base> aliases;
public ExecutionContext(Object appInfo, Base resource, Base context, Map<String, Base> aliases, Base thisItem) { public ExecutionContext(Object appInfo, Base resource, Base rootResource, Base context, Map<String, Base> aliases, Base thisItem) {
this.appInfo = appInfo; this.appInfo = appInfo;
this.context = context; this.context = context;
this.resource = resource; this.focusResource = resource;
this.rootResource = rootResource;
this.aliases = aliases; this.aliases = aliases;
this.thisItem = thisItem; this.thisItem = thisItem;
} }
public Base getResource() { public Base getFocusResource() {
return resource; return focusResource;
}
public Base getRootResource() {
return rootResource;
} }
public Base getThisItem() { public Base getThisItem() {
return thisItem; return thisItem;
@ -1312,9 +1317,13 @@ public class FHIRPathEngine {
else if (s.equals("%ucum")) else if (s.equals("%ucum"))
return new StringType("http://unitsofmeasure.org").noExtensions(); return new StringType("http://unitsofmeasure.org").noExtensions();
else if (s.equals("%resource")) { else if (s.equals("%resource")) {
if (context.resource == null) if (context.focusResource == null)
throw new PathEngineException("Cannot use %resource in this context"); throw new PathEngineException("Cannot use %resource in this context");
return context.resource; return context.focusResource;
} else if (s.equals("%rootResource")) {
if (context.rootResource == null)
throw new PathEngineException("Cannot use %rootResource in this context");
return context.rootResource;
} else if (s.equals("%context")) { } else if (s.equals("%context")) {
return context.context; return context.context;
} else if (s.equals("%us-zip")) } else if (s.equals("%us-zip"))
@ -2280,6 +2289,10 @@ public class FHIRPathEngine {
if (context.resource == null) if (context.resource == null)
throw new PathEngineException("%resource cannot be used in this context"); throw new PathEngineException("%resource cannot be used in this context");
return new TypeDetails(CollectionStatus.SINGLETON, context.resource); return new TypeDetails(CollectionStatus.SINGLETON, context.resource);
} else if (s.equals("%rootResource")) {
if (context.resource == null)
throw new PathEngineException("%rootResource cannot be used in this context");
return new TypeDetails(CollectionStatus.SINGLETON, context.resource);
} else if (s.equals("%context")) { } else if (s.equals("%context")) {
return context.context; return context.context;
} else if (s.equals("%map-codes")) } else if (s.equals("%map-codes"))
@ -2814,7 +2827,7 @@ public class FHIRPathEngine {
private ExecutionContext changeThis(ExecutionContext context, Base newThis) { private ExecutionContext changeThis(ExecutionContext context, Base newThis) {
return new ExecutionContext(context.appInfo, context.resource, context.context, context.aliases, newThis); return new ExecutionContext(context.appInfo, context.focusResource, context.rootResource, context.context, context.aliases, newThis);
} }
private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) { private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) {
@ -3286,7 +3299,7 @@ public class FHIRPathEngine {
if (s != null) { if (s != null) {
Base res = null; Base res = null;
if (s.startsWith("#")) { if (s.startsWith("#")) {
Property p = context.resource.getChildByName("contained"); Property p = context.rootResource.getChildByName("contained");
for (Base c : p.getValues()) { for (Base c : p.getValues()) {
if (chompHash(s).equals(chompHash(c.getIdBase()))) { if (chompHash(s).equals(chompHash(c.getIdBase()))) {
res = c; res = c;

View File

@ -489,7 +489,7 @@ public class GraphQLEngine {
if (expression == magicExpression) if (expression == magicExpression)
ss = suffix+'.'+Integer.toString(index); ss = suffix+'.'+Integer.toString(index);
else else
ss = suffix+'.'+fpe.evaluateToString(null, null, value, expression); ss = suffix+'.'+fpe.evaluateToString(null, null, null, value, expression);
if (!sel.getField().hasDirective("flatten")) if (!sel.getField().hasDirective("flatten"))
arg = target.addField(sel.getField().getAlias()+suffix, listStatus(sel.getField(), prop.isList() || inheritedList)); arg = target.addField(sel.getField().getAlias()+suffix, listStatus(sel.getField(), prop.isList() || inheritedList));
} }

View File

@ -126,7 +126,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(statement); compiled = engine.parse(statement);
b.append(engine.evaluateToString(ctxt, resource, resource, compiled)); b.append(engine.evaluateToString(ctxt, resource, resource, resource, compiled));
} }
} }
@ -140,7 +140,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(condition); compiled = engine.parse(condition);
boolean ok = engine.evaluateToBoolean(ctxt, resource, resource, compiled); boolean ok = engine.evaluateToBoolean(ctxt, resource, resource, resource, compiled);
List<LiquidNode> list = ok ? thenBody : elseBody; List<LiquidNode> list = ok ? thenBody : elseBody;
for (LiquidNode n : list) { for (LiquidNode n : list) {
n.evaluate(b, resource, ctxt); n.evaluate(b, resource, ctxt);
@ -157,7 +157,7 @@ public class LiquidEngine implements IEvaluationContext {
public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException { public void evaluate(StringBuilder b, Resource resource, LiquidEngineContext ctxt) throws FHIRException {
if (compiled == null) if (compiled == null)
compiled = engine.parse(condition); compiled = engine.parse(condition);
List<Base> list = engine.evaluate(ctxt, resource, resource, compiled); List<Base> list = engine.evaluate(ctxt, resource, resource, resource, compiled);
LiquidEngineContext lctxt = new LiquidEngineContext(ctxt); LiquidEngineContext lctxt = new LiquidEngineContext(ctxt);
for (Base o : list) { for (Base o : list) {
lctxt.vars.put(varName, o); lctxt.vars.put(varName, o);
@ -181,7 +181,7 @@ public class LiquidEngine implements IEvaluationContext {
Tuple incl = new Tuple(); Tuple incl = new Tuple();
nctxt.vars.put("include", incl); nctxt.vars.put("include", incl);
for (String s : params.keySet()) { for (String s : params.keySet()) {
incl.addProperty(s, engine.evaluate(ctxt, resource, resource, params.get(s))); incl.addProperty(s, engine.evaluate(ctxt, resource, resource, resource, params.get(s)));
} }
for (LiquidNode n : doc.body) { for (LiquidNode n : doc.body) {
n.evaluate(b, resource, nctxt); n.evaluate(b, resource, nctxt);

View File

@ -1687,7 +1687,7 @@ public class StructureMapUtilities {
expr = fpe.parse(src.getElement()); expr = fpe.parse(src.getElement());
src.setUserData(MAP_SEARCH_EXPRESSION, expr); src.setUserData(MAP_SEARCH_EXPRESSION, expr);
} }
String search = fpe.evaluateToString(vars, null, new StringType(), expr); // string is a holder of nothing to ensure that variables are processed correctly String search = fpe.evaluateToString(vars, null, null, new StringType(), expr); // string is a holder of nothing to ensure that variables are processed correctly
items = services.performSearch(context.appInfo, search); items = services.performSearch(context.appInfo, search);
} else { } else {
items = new ArrayList<Base>(); items = new ArrayList<Base>();
@ -1723,7 +1723,7 @@ public class StructureMapUtilities {
} }
List<Base> remove = new ArrayList<Base>(); List<Base> remove = new ArrayList<Base>();
for (Base item : items) { for (Base item : items) {
if (!fpe.evaluateToBoolean(vars, null, item, expr)) { if (!fpe.evaluateToBoolean(vars, null, null, item, expr)) {
log(indent+" condition ["+src.getCondition()+"] for "+item.toString()+" : false"); log(indent+" condition ["+src.getCondition()+"] for "+item.toString()+" : false");
remove.add(item); remove.add(item);
} else } else
@ -1741,7 +1741,7 @@ public class StructureMapUtilities {
} }
List<Base> remove = new ArrayList<Base>(); List<Base> remove = new ArrayList<Base>();
for (Base item : items) { for (Base item : items) {
if (!fpe.evaluateToBoolean(vars, null, item, expr)) if (!fpe.evaluateToBoolean(vars, null, null, item, expr))
throw new FHIRException("Rule \""+ruleId+"\": Check condition failed"); throw new FHIRException("Rule \""+ruleId+"\": Check condition failed");
} }
} }
@ -1755,7 +1755,7 @@ public class StructureMapUtilities {
} }
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Base item : items) for (Base item : items)
b.appendIfNotNull(fpe.evaluateToString(vars, null, item, expr)); b.appendIfNotNull(fpe.evaluateToString(vars, null, null, item, expr));
if (b.length() > 0) if (b.length() > 0)
services.log(b.toString()); services.log(b.toString());
} }
@ -1875,7 +1875,7 @@ public class StructureMapUtilities {
expr = fpe.parse(getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString())); expr = fpe.parse(getParamStringNoNull(vars, tgt.getParameter().get(1), tgt.toString()));
tgt.setUserData(MAP_WHERE_EXPRESSION, expr); tgt.setUserData(MAP_WHERE_EXPRESSION, expr);
} }
List<Base> v = fpe.evaluate(vars, null, tgt.getParameter().size() == 2 ? getParam(vars, tgt.getParameter().get(0)) : new BooleanType(false), expr); List<Base> v = fpe.evaluate(vars, null, null, tgt.getParameter().size() == 2 ? getParam(vars, tgt.getParameter().get(0)) : new BooleanType(false), expr);
if (v.size() == 0) if (v.size() == 0)
return null; return null;
else if (v.size() != 1) else if (v.size() != 1)

View File

@ -413,7 +413,8 @@ public class SnapShotGenerationTests {
else else
testSort(); testSort();
for (Rule r : test.getRules()) { for (Rule r : test.getRules()) {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), r.expression); StructureDefinition sdn = new StructureDefinition();
boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, r.expression);
Assert.assertTrue(r.description, ok); Assert.assertTrue(r.description, ok);
} }
} }

View File

@ -157,16 +157,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Object appContext; private Object appContext;
private Element container; // bundle, or parameters private Element container; // bundle, or parameters
private Element resource; private Element resource;
private Element rootResource;
public ValidatorHostContext(Object appContext) { public ValidatorHostContext(Object appContext) {
this.appContext = appContext; this.appContext = appContext;
} }
public ValidatorHostContext(Object appContext, Element element) { public ValidatorHostContext(Object appContext, Element element) {
this.appContext = appContext; this.appContext = appContext;
this.resource = element; this.resource = element;
this.rootResource = element;
} }
public ValidatorHostContext forContained(Element element) { public ValidatorHostContext forContained(Element element) {
ValidatorHostContext res = new ValidatorHostContext(appContext); ValidatorHostContext res = new ValidatorHostContext(appContext);
res.rootResource = resource;
res.resource = element; res.resource = element;
return res; return res;
} }
@ -2618,7 +2622,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean ok; boolean ok;
try { try {
long t = System.nanoTime(); long t = System.nanoTime();
ok = fpe.evaluateToBoolean(hostContext, hostContext.resource, element, n); ok = fpe.evaluateToBoolean(hostContext, hostContext.resource, hostContext.rootResource, element, n);
fpeTime = fpeTime + (System.nanoTime() - t); fpeTime = fpeTime + (System.nanoTime() - t);
msg = fpe.forLog(); msg = fpe.forLog();
} catch (Exception ex) { } catch (Exception ex) {
@ -3972,7 +3976,7 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
boolean ok; boolean ok;
try { try {
long t = System.nanoTime(); long t = System.nanoTime();
ok = fpe.evaluateToBoolean(hostContext, resource, element, n); ok = fpe.evaluateToBoolean(hostContext, resource, hostContext.rootResource, element, n);
fpeTime = fpeTime + (System.nanoTime() - t); fpeTime = fpeTime + (System.nanoTime() - t);
msg = fpe.forLog(); msg = fpe.forLog();
} catch (Exception ex) { } catch (Exception ex) {

View File

@ -169,6 +169,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Object appContext; private Object appContext;
private Element container; // bundle, or parameters private Element container; // bundle, or parameters
private Element resource; private Element resource;
private Element rootResource;
private StructureDefinition profile; // the profile that contains the content being validated private StructureDefinition profile; // the profile that contains the content being validated
public ValidatorHostContext(Object appContext) { public ValidatorHostContext(Object appContext) {
this.appContext = appContext; this.appContext = appContext;
@ -176,10 +177,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public ValidatorHostContext(Object appContext, Element element) { public ValidatorHostContext(Object appContext, Element element) {
this.appContext = appContext; this.appContext = appContext;
this.resource = element; this.resource = element;
this.rootResource = element;
} }
public ValidatorHostContext forContained(Element element) { public ValidatorHostContext forContained(Element element) {
ValidatorHostContext res = new ValidatorHostContext(appContext); ValidatorHostContext res = new ValidatorHostContext(appContext);
res.rootResource = resource;
res.resource = element; res.resource = element;
res.container = resource; res.container = resource;
res.profile = profile; res.profile = profile;
@ -189,6 +192,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public ValidatorHostContext forProfile(StructureDefinition profile) { public ValidatorHostContext forProfile(StructureDefinition profile) {
ValidatorHostContext res = new ValidatorHostContext(appContext); ValidatorHostContext res = new ValidatorHostContext(appContext);
res.resource = resource; res.resource = resource;
res.rootResource = rootResource;
res.container = container; res.container = container;
res.profile = profile; res.profile = profile;
return res; return res;
@ -2787,7 +2791,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean ok; boolean ok;
try { try {
long t = System.nanoTime(); long t = System.nanoTime();
ok = fpe.evaluateToBoolean(hostContext.forProfile(profile), hostContext.resource, element, n); ok = fpe.evaluateToBoolean(hostContext.forProfile(profile), hostContext.resource, hostContext.rootResource, element, n);
fpeTime = fpeTime + (System.nanoTime() - t); fpeTime = fpeTime + (System.nanoTime() - t);
msg = fpe.forLog(); msg = fpe.forLog();
} catch (Exception ex) { } catch (Exception ex) {
@ -4389,7 +4393,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
boolean ok; boolean ok;
try { try {
long t = System.nanoTime(); long t = System.nanoTime();
ok = fpe.evaluateToBoolean(hostContext, resource, element, n); ok = fpe.evaluateToBoolean(hostContext, resource, hostContext.rootResource, element, n);
fpeTime = fpeTime + (System.nanoTime() - t); fpeTime = fpeTime + (System.nanoTime() - t);
msg = fpe.forLog(); msg = fpe.forLog();
} catch (Exception ex) { } catch (Exception ex) {