base components of implementing the defineVariable fhirpath function
This commit is contained in:
parent
890737e17b
commit
7b7af6087e
|
@ -51,7 +51,7 @@ public class ExpressionNode {
|
||||||
|
|
||||||
Empty, Not, Exists, SubsetOf, SupersetOf, IsDistinct, Distinct, Count, Where, Select, All, Repeat, Aggregate, Item /*implicit from name[]*/, As, Is, Single,
|
Empty, Not, Exists, SubsetOf, SupersetOf, IsDistinct, Distinct, Count, Where, Select, All, Repeat, Aggregate, Item /*implicit from name[]*/, As, Is, Single,
|
||||||
First, Last, Tail, Skip, Take, Union, Combine, Intersect, Exclude, Iif, Upper, Lower, ToChars, IndexOf, Substring, StartsWith, EndsWith, Matches, MatchesFull, ReplaceMatches, Contains, Replace, Length,
|
First, Last, Tail, Skip, Take, Union, Combine, Intersect, Exclude, Iif, Upper, Lower, ToChars, IndexOf, Substring, StartsWith, EndsWith, Matches, MatchesFull, ReplaceMatches, Contains, Replace, Length,
|
||||||
Children, Descendants, MemberOf, Trace, Check, Today, Now, Resolve, Extension, AllFalse, AnyFalse, AllTrue, AnyTrue,
|
Children, Descendants, MemberOf, Trace, DefineVariable, Check, Today, Now, Resolve, Extension, AllFalse, AnyFalse, AllTrue, AnyTrue,
|
||||||
HasValue, OfType, Type, ConvertsToBoolean, ConvertsToInteger, ConvertsToString, ConvertsToDecimal, ConvertsToQuantity, ConvertsToDateTime, ConvertsToDate, ConvertsToTime, ToBoolean, ToInteger, ToString, ToDecimal, ToQuantity, ToDateTime, ToTime, ConformsTo,
|
HasValue, OfType, Type, ConvertsToBoolean, ConvertsToInteger, ConvertsToString, ConvertsToDecimal, ConvertsToQuantity, ConvertsToDateTime, ConvertsToDate, ConvertsToTime, ToBoolean, ToInteger, ToString, ToDecimal, ToQuantity, ToDateTime, ToTime, ConformsTo,
|
||||||
Round, Sqrt, Abs, Ceiling, Exp, Floor, Ln, Log, Power, Truncate,
|
Round, Sqrt, Abs, Ceiling, Exp, Floor, Ln, Log, Power, Truncate,
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ public class ExpressionNode {
|
||||||
if (name.equals("descendants")) return Function.Descendants;
|
if (name.equals("descendants")) return Function.Descendants;
|
||||||
if (name.equals("memberOf")) return Function.MemberOf;
|
if (name.equals("memberOf")) return Function.MemberOf;
|
||||||
if (name.equals("trace")) return Function.Trace;
|
if (name.equals("trace")) return Function.Trace;
|
||||||
|
if (name.equals("defineVariable")) return Function.DefineVariable;
|
||||||
if (name.equals("check")) return Function.Check;
|
if (name.equals("check")) return Function.Check;
|
||||||
if (name.equals("today")) return Function.Today;
|
if (name.equals("today")) return Function.Today;
|
||||||
if (name.equals("now")) return Function.Now;
|
if (name.equals("now")) return Function.Now;
|
||||||
|
@ -211,6 +212,7 @@ public class ExpressionNode {
|
||||||
case Descendants : return "descendants";
|
case Descendants : return "descendants";
|
||||||
case MemberOf : return "memberOf";
|
case MemberOf : return "memberOf";
|
||||||
case Trace : return "trace";
|
case Trace : return "trace";
|
||||||
|
case DefineVariable : return "defineVariable";
|
||||||
case Check : return "check";
|
case Check : return "check";
|
||||||
case Today : return "today";
|
case Today : return "today";
|
||||||
case Now : return "now";
|
case Now : return "now";
|
||||||
|
|
|
@ -193,6 +193,7 @@ public class FHIRPathEngine {
|
||||||
/**
|
/**
|
||||||
* A constant reference - e.g. a reference to a name that must be resolved in context.
|
* A constant reference - e.g. a reference to a name that must be resolved in context.
|
||||||
* The % will be removed from the constant name before this is invoked.
|
* The % will be removed from the constant name before this is invoked.
|
||||||
|
* Variables created with defineVariable will not be processed by resolveConstant (or resolveConstantType)
|
||||||
*
|
*
|
||||||
* This will also be called if the host invokes the FluentPath engine with a context of null
|
* This will also be called if the host invokes the FluentPath engine with a context of null
|
||||||
*
|
*
|
||||||
|
@ -998,6 +999,7 @@ public class FHIRPathEngine {
|
||||||
private List<Base> total;
|
private List<Base> total;
|
||||||
private Map<String, Base> aliases;
|
private Map<String, Base> aliases;
|
||||||
private int index;
|
private int index;
|
||||||
|
private Map<String, List<Base>> definedVariables;
|
||||||
|
|
||||||
public ExecutionContext(Object appInfo, Base resource, Base rootResource, 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;
|
||||||
|
@ -1046,6 +1048,19 @@ public class FHIRPathEngine {
|
||||||
index = i;
|
index = i;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasDefinedVariable(String name) {
|
||||||
|
return definedVariables != null && definedVariables.containsKey(name);
|
||||||
|
}
|
||||||
|
public List<Base> getDefinedVariable(String name) {
|
||||||
|
return definedVariables == null ? makeNull() : definedVariables.get(name);
|
||||||
|
}
|
||||||
|
public void setDefinedVariable(String name, List<Base> value) {
|
||||||
|
if (definedVariables == null) {
|
||||||
|
definedVariables = new HashMap<String, List<Base>>();
|
||||||
|
}
|
||||||
|
definedVariables.put(name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ExecutionTypeContext {
|
private static class ExecutionTypeContext {
|
||||||
|
@ -1054,7 +1069,7 @@ public class FHIRPathEngine {
|
||||||
private TypeDetails context;
|
private TypeDetails context;
|
||||||
private TypeDetails thisItem;
|
private TypeDetails thisItem;
|
||||||
private TypeDetails total;
|
private TypeDetails total;
|
||||||
|
private Map<String, TypeDetails> definedVariables;
|
||||||
|
|
||||||
public ExecutionTypeContext(Object appInfo, String resource, TypeDetails context, TypeDetails thisItem) {
|
public ExecutionTypeContext(Object appInfo, String resource, TypeDetails context, TypeDetails thisItem) {
|
||||||
super();
|
super();
|
||||||
|
@ -1071,7 +1086,24 @@ public class FHIRPathEngine {
|
||||||
return thisItem;
|
return thisItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasDefinedVariable(String name) {
|
||||||
|
return definedVariables != null && definedVariables.containsKey(name);
|
||||||
|
}
|
||||||
|
public TypeDetails getDefinedVariable(String name) {
|
||||||
|
return definedVariables == null ? null : definedVariables.get(name);
|
||||||
|
}
|
||||||
|
public void setDefinedVariable(String name, TypeDetails value) {
|
||||||
|
if (definedVariables == null) {
|
||||||
|
definedVariables = new HashMap<String, TypeDetails>();
|
||||||
|
} else {
|
||||||
|
if (definedVariables.containsKey(name)) {
|
||||||
|
// Can't do this, so throw an error
|
||||||
|
throw new PathEngineException("Redefine of variable "+name, I18nConstants.FHIRPATH_REDEFINE_VARIABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
definedVariables.put(name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode parseExpression(FHIRLexer lexer, boolean proximal) throws FHIRLexerException {
|
private ExpressionNode parseExpression(FHIRLexer lexer, boolean proximal) throws FHIRLexerException {
|
||||||
|
@ -1411,6 +1443,7 @@ public class FHIRPathEngine {
|
||||||
case Descendants: return checkParamCount(lexer, location, exp, 0);
|
case Descendants: return checkParamCount(lexer, location, exp, 0);
|
||||||
case MemberOf: return checkParamCount(lexer, location, exp, 1);
|
case MemberOf: return checkParamCount(lexer, location, exp, 1);
|
||||||
case Trace: return checkParamCount(lexer, location, exp, 1, 2);
|
case Trace: return checkParamCount(lexer, location, exp, 1, 2);
|
||||||
|
case DefineVariable: return checkParamCount(lexer, location, exp, 1, 2);
|
||||||
case Check: return checkParamCount(lexer, location, exp, 2);
|
case Check: return checkParamCount(lexer, location, exp, 2);
|
||||||
case Today: return checkParamCount(lexer, location, exp, 0);
|
case Today: return checkParamCount(lexer, location, exp, 0);
|
||||||
case Now: return checkParamCount(lexer, location, exp, 0);
|
case Now: return checkParamCount(lexer, location, exp, 0);
|
||||||
|
@ -1664,6 +1697,10 @@ public class FHIRPathEngine {
|
||||||
}
|
}
|
||||||
FHIRConstant c = (FHIRConstant) constant;
|
FHIRConstant c = (FHIRConstant) constant;
|
||||||
if (c.getValue().startsWith("%")) {
|
if (c.getValue().startsWith("%")) {
|
||||||
|
String varName = c.getValue().substring(1);
|
||||||
|
if (context.hasDefinedVariable(varName)) {
|
||||||
|
return context.getDefinedVariable(varName);
|
||||||
|
}
|
||||||
return resolveConstant(context, c.getValue(), beforeContext, expr, true);
|
return resolveConstant(context, c.getValue(), beforeContext, expr, true);
|
||||||
} else if (c.getValue().startsWith("@")) {
|
} else if (c.getValue().startsWith("@")) {
|
||||||
return new ArrayList<Base>(Arrays.asList(processDateConstant(context.appInfo, c.getValue().substring(1), expr)));
|
return new ArrayList<Base>(Arrays.asList(processDateConstant(context.appInfo, c.getValue().substring(1), expr)));
|
||||||
|
@ -3139,6 +3176,10 @@ public class FHIRPathEngine {
|
||||||
} else if (hostServices == null) {
|
} else if (hostServices == null) {
|
||||||
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s);
|
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s);
|
||||||
} else {
|
} else {
|
||||||
|
String varName = s.substring(1);
|
||||||
|
if (context.hasDefinedVariable(varName)) {
|
||||||
|
return context.getDefinedVariable(varName);
|
||||||
|
}
|
||||||
TypeDetails v = hostServices.resolveConstantType(this, context.appInfo, s, explicitConstant);
|
TypeDetails v = hostServices.resolveConstantType(this, context.appInfo, s, explicitConstant);
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s);
|
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s);
|
||||||
|
@ -3722,7 +3763,7 @@ public class FHIRPathEngine {
|
||||||
case 0:
|
case 0:
|
||||||
return exp.getFunction() == Function.Where || exp.getFunction() == Function.Exists || exp.getFunction() == Function.All || exp.getFunction() == Function.Select || exp.getFunction() == Function.Repeat || exp.getFunction() == Function.Aggregate;
|
return exp.getFunction() == Function.Where || exp.getFunction() == Function.Exists || exp.getFunction() == Function.All || exp.getFunction() == Function.Select || exp.getFunction() == Function.Repeat || exp.getFunction() == Function.Aggregate;
|
||||||
case 1:
|
case 1:
|
||||||
return exp.getFunction() == Function.Trace;
|
return exp.getFunction() == Function.Trace || exp.getFunction() == Function.DefineVariable;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3875,6 +3916,7 @@ public class FHIRPathEngine {
|
||||||
case Descendants : return funcDescendants(context, focus, exp);
|
case Descendants : return funcDescendants(context, focus, exp);
|
||||||
case MemberOf : return funcMemberOf(context, focus, exp);
|
case MemberOf : return funcMemberOf(context, focus, exp);
|
||||||
case Trace : return funcTrace(context, focus, exp);
|
case Trace : return funcTrace(context, focus, exp);
|
||||||
|
case DefineVariable : return funcDefineVariable(context, focus, exp);
|
||||||
case Check : return funcCheck(context, focus, exp);
|
case Check : return funcCheck(context, focus, exp);
|
||||||
case Today : return funcToday(context, focus, exp);
|
case Today : return funcToday(context, focus, exp);
|
||||||
case Now : return funcNow(context, focus, exp);
|
case Now : return funcNow(context, focus, exp);
|
||||||
|
@ -4640,13 +4682,48 @@ public class FHIRPathEngine {
|
||||||
|
|
||||||
|
|
||||||
private ExecutionContext changeThis(ExecutionContext context, Base newThis) {
|
private ExecutionContext changeThis(ExecutionContext context, Base newThis) {
|
||||||
return new ExecutionContext(context.appInfo, context.focusResource, context.rootResource, context.context, context.aliases, newThis);
|
ExecutionContext newContext = new ExecutionContext(context.appInfo, context.focusResource, context.rootResource, context.context, context.aliases, newThis);
|
||||||
|
// append all of the defined variables from the context into the new context
|
||||||
|
if (context.definedVariables != null) {
|
||||||
|
for (String s : context.definedVariables.keySet()) {
|
||||||
|
newContext.setDefinedVariable(s, context.definedVariables.get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecutionContext contextForParameter(ExecutionContext context) {
|
||||||
|
ExecutionContext newContext = new ExecutionContext(context.appInfo, context.focusResource, context.rootResource, context.context, context.aliases, context.thisItem);
|
||||||
|
// append all of the defined variables from the context into the new context
|
||||||
|
if (context.definedVariables != null) {
|
||||||
|
for (String s : context.definedVariables.keySet()) {
|
||||||
|
newContext.setDefinedVariable(s, context.definedVariables.get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) {
|
private ExecutionTypeContext changeThis(ExecutionTypeContext context, TypeDetails newThis) {
|
||||||
return new ExecutionTypeContext(context.appInfo, context.resource, context.context, newThis);
|
ExecutionTypeContext newContext = new ExecutionTypeContext(context.appInfo, context.resource, context.context, newThis);
|
||||||
|
// append all of the defined variables from the context into the new context
|
||||||
|
if (context.definedVariables != null) {
|
||||||
|
for (String s : context.definedVariables.keySet()) {
|
||||||
|
newContext.setDefinedVariable(s, context.definedVariables.get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ExecutionTypeContext contextForParameter(ExecutionTypeContext context) {
|
||||||
|
ExecutionTypeContext newContext = new ExecutionTypeContext(context.appInfo, context.resource, context.context, context.thisItem);
|
||||||
|
// append all of the defined variables from the context into the new context
|
||||||
|
if (context.definedVariables != null) {
|
||||||
|
for (String s : context.definedVariables.keySet()) {
|
||||||
|
newContext.setDefinedVariable(s, context.definedVariables.get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newContext;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Base> funcNow(ExecutionContext context, List<Base> focus, ExpressionNode exp) {
|
private List<Base> funcNow(ExecutionContext context, List<Base> focus, ExpressionNode exp) {
|
||||||
List<Base> result = new ArrayList<Base>();
|
List<Base> result = new ArrayList<Base>();
|
||||||
|
@ -5484,6 +5561,20 @@ public class FHIRPathEngine {
|
||||||
return focus;
|
return focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Base> funcDefineVariable(ExecutionContext context, List<Base> focus, ExpressionNode exp) throws FHIRException {
|
||||||
|
List<Base> nl = execute(context, focus, exp.getParameters().get(0), true);
|
||||||
|
String name = nl.get(0).primitiveValue();
|
||||||
|
List<Base> value;
|
||||||
|
if (exp.getParameters().size() == 2) {
|
||||||
|
value = execute(context, focus, exp.getParameters().get(1), true);
|
||||||
|
} else {
|
||||||
|
value = focus;
|
||||||
|
}
|
||||||
|
// stash the variable into the context
|
||||||
|
context.setDefinedVariable(name, value);
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Base> funcCheck(ExecutionContext context, List<Base> focus, ExpressionNode expr) throws FHIRException {
|
private List<Base> funcCheck(ExecutionContext context, List<Base> focus, ExpressionNode expr) throws FHIRException {
|
||||||
List<Base> n1 = execute(context, focus, expr.getParameters().get(0), true);
|
List<Base> n1 = execute(context, focus, expr.getParameters().get(0), true);
|
||||||
if (!convertToBoolean(n1)) {
|
if (!convertToBoolean(n1)) {
|
||||||
|
|
|
@ -1102,6 +1102,7 @@ public class I18nConstants {
|
||||||
public static final String SD_ELEMENT_FIXED_WRONG_TYPE = "SD_ELEMENT_FIXED_WRONG_TYPE";
|
public static final String SD_ELEMENT_FIXED_WRONG_TYPE = "SD_ELEMENT_FIXED_WRONG_TYPE";
|
||||||
public static final String SD_ELEMENT_REASON_DERIVED = "SD_ELEMENT_REASON_DERIVED";
|
public static final String SD_ELEMENT_REASON_DERIVED = "SD_ELEMENT_REASON_DERIVED";
|
||||||
public static final String SD_ELEMENT_PATTERN_WRONG_TYPE = "SD_ELEMENT_PATTERN_WRONG_TYPE";
|
public static final String SD_ELEMENT_PATTERN_WRONG_TYPE = "SD_ELEMENT_PATTERN_WRONG_TYPE";
|
||||||
|
public static final String FHIRPATH_REDEFINE_VARIABLE = "FHIRPATH_REDEFINE_VARIABLE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1084,6 +1084,7 @@ TX_GENERAL_CC_ERROR_MESSAGE = No valid coding was found for the value set ''{0}'
|
||||||
Validation_VAL_Profile_Minimum_SLICE_one = Slice ''{3}'': a matching slice is required, but not found (from {1}). Note that other slices are allowed in addition to this required slice
|
Validation_VAL_Profile_Minimum_SLICE_one = Slice ''{3}'': a matching slice is required, but not found (from {1}). Note that other slices are allowed in addition to this required slice
|
||||||
Validation_VAL_Profile_Minimum_SLICE_other = Slice ''{3}'': minimum required = {0}, but only found {7} (from {1})
|
Validation_VAL_Profile_Minimum_SLICE_other = Slice ''{3}'': minimum required = {0}, but only found {7} (from {1})
|
||||||
FHIRPATH_UNKNOWN_EXTENSION = Reference to an unknown extension - double check that the URL ''{0}'' is correct
|
FHIRPATH_UNKNOWN_EXTENSION = Reference to an unknown extension - double check that the URL ''{0}'' is correct
|
||||||
|
FHIRPATH_REDEFINE_VARIABLE = The variable ''{0}'' cannot be redefined
|
||||||
Type_Specific_Checks_DT_XHTML_Resolve = Hyperlink ''{0}'' at ''{1}'' for ''{2}''' does not resolve
|
Type_Specific_Checks_DT_XHTML_Resolve = Hyperlink ''{0}'' at ''{1}'' for ''{2}''' does not resolve
|
||||||
Type_Specific_Checks_DT_XHTML_Resolve_Img = Image source ''{0}'' at ''{1}'' does not resolve
|
Type_Specific_Checks_DT_XHTML_Resolve_Img = Image source ''{0}'' at ''{1}'' does not resolve
|
||||||
TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES = Hyperlink ''{0}'' at ''{1}'' for ''{2}'' resolves to multiple targets ({3})
|
TYPE_SPECIFIC_CHECKS_DT_XHTML_MULTIPLE_MATCHES = Hyperlink ''{0}'' at ''{1}'' for ''{2}'' resolves to multiple targets ({3})
|
||||||
|
|
Loading…
Reference in New Issue