liquid fixes to FHIRPath
This commit is contained in:
parent
e2dff7d118
commit
2f0a45046e
|
@ -76,6 +76,7 @@ public class FHIRLexer {
|
||||||
private SourceLocation currentStartLocation;
|
private SourceLocation currentStartLocation;
|
||||||
private int id;
|
private int id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private boolean liquidMode; // in liquid mode, || terminates the expression and hands the parser back to the host
|
||||||
|
|
||||||
public FHIRLexer(String source, String name) throws FHIRLexerException {
|
public FHIRLexer(String source, String name) throws FHIRLexerException {
|
||||||
this.source = source == null ? "" : source;
|
this.source = source == null ? "" : source;
|
||||||
|
@ -272,6 +273,12 @@ public class FHIRLexer {
|
||||||
throw error("Unterminated string");
|
throw error("Unterminated string");
|
||||||
cursor++;
|
cursor++;
|
||||||
current = "`"+source.substring(currentStart+1, cursor-1)+"`";
|
current = "`"+source.substring(currentStart+1, cursor-1)+"`";
|
||||||
|
} else if (ch == '|' && liquidMode) {
|
||||||
|
cursor++;
|
||||||
|
ch = source.charAt(cursor);
|
||||||
|
if (ch == '|')
|
||||||
|
cursor++;
|
||||||
|
current = source.substring(currentStart, cursor);
|
||||||
} else if (ch == '@'){
|
} else if (ch == '@'){
|
||||||
int start = cursor;
|
int start = cursor;
|
||||||
cursor++;
|
cursor++;
|
||||||
|
@ -520,5 +527,11 @@ public class FHIRLexer {
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
public boolean isLiquidMode() {
|
||||||
|
return liquidMode;
|
||||||
|
}
|
||||||
|
public void setLiquidMode(boolean liquidMode) {
|
||||||
|
this.liquidMode = liquidMode;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -262,6 +262,7 @@ public class FHIRPathEngine {
|
||||||
private String location; // for error messages
|
private String location; // for error messages
|
||||||
private boolean allowPolymorphicNames;
|
private boolean allowPolymorphicNames;
|
||||||
private boolean doImplicitStringConversion;
|
private boolean doImplicitStringConversion;
|
||||||
|
private boolean liquidMode; // in liquid mode, || terminates the expression and hands the parser back to the host
|
||||||
|
|
||||||
// if the fhir path expressions are allowed to use constants beyond those defined in the specification
|
// if the fhir path expressions are allowed to use constants beyond those defined in the specification
|
||||||
// the application can implement them by providing a constant resolver
|
// the application can implement them by providing a constant resolver
|
||||||
|
@ -6034,5 +6035,13 @@ public class FHIRPathEngine {
|
||||||
this.allowPolymorphicNames = allowPolymorphicNames;
|
this.allowPolymorphicNames = allowPolymorphicNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLiquidMode() {
|
||||||
|
return liquidMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLiquidMode(boolean liquidMode) {
|
||||||
|
this.liquidMode = liquidMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ public class LiquidEngine implements IEvaluationContext {
|
||||||
this.externalHostServices = hostServices;
|
this.externalHostServices = hostServices;
|
||||||
engine = new FHIRPathEngine(context);
|
engine = new FHIRPathEngine(context);
|
||||||
engine.setHostServices(this);
|
engine.setHostServices(this);
|
||||||
|
engine.setLiquidMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILiquidEngineIncludeResolver getIncludeResolver() {
|
public ILiquidEngineIncludeResolver getIncludeResolver() {
|
||||||
|
@ -152,22 +153,82 @@ public class LiquidEngine implements IEvaluationContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum LiquidFilter {
|
||||||
|
PREPEND;
|
||||||
|
|
||||||
|
public static LiquidFilter fromCode(String code) {
|
||||||
|
if ("prepend".equals(code)) {
|
||||||
|
return PREPEND;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LiquidExpressionNode {
|
||||||
|
private LiquidFilter filter; // null at root
|
||||||
|
private ExpressionNode expression; // null for some filters
|
||||||
|
public LiquidExpressionNode(LiquidFilter filter, ExpressionNode expression) {
|
||||||
|
super();
|
||||||
|
this.filter = filter;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private class LiquidStatement extends LiquidNode {
|
private class LiquidStatement extends LiquidNode {
|
||||||
private String statement;
|
private String statement;
|
||||||
private ExpressionNode compiled;
|
private List<LiquidExpressionNode> compiled = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) throws FHIRException {
|
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) throws FHIRException {
|
||||||
if (compiled == null)
|
if (compiled.size() == 0) {
|
||||||
compiled = engine.parse(statement);
|
FHIRLexer lexer = new FHIRLexer(statement, "liquid statement");
|
||||||
List<Base> items = engine.evaluate(ctxt, resource, resource, resource, compiled);
|
lexer.setLiquidMode(true);
|
||||||
|
compiled.add(new LiquidExpressionNode(null, engine.parse(lexer)));
|
||||||
|
while (!lexer.done()) {
|
||||||
|
if (lexer.getCurrent().equals("||")) {
|
||||||
|
lexer.next();
|
||||||
|
String f = lexer.getCurrent();
|
||||||
|
LiquidFilter filter = LiquidFilter.fromCode(f);
|
||||||
|
if (filter == null) {
|
||||||
|
lexer.error("Unknown Liquid filter '"+f+"'");
|
||||||
|
}
|
||||||
|
lexer.next();
|
||||||
|
if (!lexer.done() && lexer.getCurrent().equals(":")) {
|
||||||
|
lexer.next();
|
||||||
|
compiled.add(new LiquidExpressionNode(filter, engine.parse(lexer)));
|
||||||
|
} else {
|
||||||
|
compiled.add(new LiquidExpressionNode(filter, null));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lexer.error("Unexpected syntax parsing liquid statement");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String t = null;
|
||||||
|
for (LiquidExpressionNode i : compiled) {
|
||||||
|
if (i.filter == null) { // first
|
||||||
|
t = stmtToString(ctxt, engine.evaluate(ctxt, resource, resource, resource, i.expression));
|
||||||
|
} else switch (i.filter) {
|
||||||
|
case PREPEND:
|
||||||
|
t = stmtToString(ctxt, engine.evaluate(ctxt, resource, resource, resource, i.expression)) + t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.append(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stmtToString(LiquidEngineContext ctxt, List<Base> items) {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Base i : items) {
|
for (Base i : items) {
|
||||||
if (first) first = false; else b.append(", ");
|
if (first) first = false; else b.append(", ");
|
||||||
String s = renderingSupport != null ? renderingSupport.renderForLiquid(ctxt.externalContext, i) : null;
|
String s = renderingSupport != null ? renderingSupport.renderForLiquid(ctxt.externalContext, i) : null;
|
||||||
b.append(s != null ? s : engine.convertToString(i));
|
b.append(s != null ? s : engine.convertToString(i));
|
||||||
}
|
}
|
||||||
|
return b.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue