From f2b619b08e5792725b5e020c7a45d2057d108f5e Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 31 Jan 2019 11:59:39 +1100 Subject: [PATCH] fix bugs in FHIRPath engine, and work around wrong FHIRPath statements in the validator --- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 21 ++++++---- .../fhir/r4/validation/InstanceValidator.java | 38 +++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index bb49fe6d4..eecc79653 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -1736,7 +1736,7 @@ public class FHIRPathEngine { return makeBoolean(!res); } - private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary"}; + private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"}; private List opLessThan(List left, List right) throws FHIRException { if (left.size() == 0 || right.size() == 0) @@ -3200,7 +3200,7 @@ public class FHIRPathEngine { private List funcIsDistinct(ExecutionContext context, List focus, ExpressionNode exp) { if (focus.size() < 1) - return new ArrayList(); + return makeBoolean(true); if (focus.size() == 1) return makeBoolean(true); @@ -4239,22 +4239,29 @@ public class FHIRPathEngine { private Equality asBool(Base item) { if (item instanceof BooleanType) return boolToTriState(((BooleanType) item).booleanValue()); - else if (item instanceof IntegerType) + else if (item.isBooleanPrimitive()) { + if (Utilities.existsInList(item.primitiveValue(), "true")) + return Equality.True; + else if (Utilities.existsInList(item.primitiveValue(), "false")) + return Equality.False; + else + return Equality.Null; + } else if (item instanceof IntegerType || Utilities.existsInList(item.fhirType(), "integer", "positiveint", "unsignedInt")) return asBoolFromInt(item.primitiveValue()); - else if (item instanceof DecimalType) + else if (item instanceof DecimalType || Utilities.existsInList(item.fhirType(), "decimal")) return asBoolFromDec(item.primitiveValue()); else if (Utilities.existsInList(item.fhirType(), FHIR_TYPES_STRING)) { if (Utilities.existsInList(item.primitiveValue(), "true", "t", "yes", "y")) - return Equality.False; - else if (Utilities.existsInList(item.primitiveValue(), "false", "f", "no", "n")) return Equality.True; + else if (Utilities.existsInList(item.primitiveValue(), "false", "f", "no", "n")) + return Equality.False; else if (Utilities.isInteger(item.primitiveValue())) return asBoolFromInt(item.primitiveValue()); else if (Utilities.isDecimal(item.primitiveValue())) return asBoolFromDec(item.primitiveValue()); else return Equality.Null; - } else + } return Equality.Null; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java index afc153552..760accbf6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java @@ -2023,7 +2023,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } ElementDefinition ed = null; - ExpressionNode expr = fpe.parse(discriminator); + ExpressionNode expr = fpe.parse(fixExpr(discriminator)); long t2 = System.nanoTime(); ed = fpe.evaluateDefinition(expr, profile, element); sdTime = sdTime + (System.nanoTime() - t2); @@ -2048,7 +2048,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (element == null) throw new DefinitionException("Unable to resolve element "+id+" in profile "+p); } - expr = fpe.parse(discriminator); + expr = fpe.parse(fixExpr(discriminator)); t2 = System.nanoTime(); ed = fpe.evaluateDefinition(expr, profile, element); sdTime = sdTime + (System.nanoTime() - t2); @@ -2586,7 +2586,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } try { - n = fpe.parse(expression.toString()); + n = fpe.parse(fixExpr(expression.toString())); } catch (FHIRLexerException e) { throw new FHIRException("Problem processing expression "+expression +" in profile " + profile.getUrl() + " path " + path + ": " + e.getMessage()); } @@ -3911,7 +3911,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (n == null) { long t = System.nanoTime(); try { - n = fpe.parse(inv.getExpression()); + n = fpe.parse(fixExpr(inv.getExpression())); } catch (FHIRLexerException e) { throw new FHIRException("Problem processing expression "+inv.getExpression() +" in profile " + profile.getUrl() + " path " + path + ": " + e.getMessage()); } @@ -3931,12 +3931,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat msg = ex.getMessage(); } if (!ok) { - // GDG 18-feb 2018 - why do it again? just to waste cycles? -// try { -// ok = fpe.evaluateToBoolean(hostContext, resource, element, n); -// } catch (PathEngineException e) { -// throw new FHIRException("Problem processing expression "+inv.getExpression() +" in profile " + profile.getUrl() + " path " + path + ": " + e.getMessage()); -// } if (!Utilities.noString(msg)) msg = " ("+msg+")"; if (inv.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice") && @@ -4311,7 +4305,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat try { ExpressionNode n = (ExpressionNode) inv.getUserData("validator.expression.cache"); if (n == null) { - n = fpe.parse(inv.getExpression()); + n = fpe.parse(fixExpr(inv.getExpression())); inv.setUserData("validator.expression.cache", n); } fpe.check(null, sd.getKind() == StructureDefinitionKind.RESOURCE ? sd.getType() : "DomainResource", ed.getPath(), n); @@ -4325,4 +4319,26 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } + private String fixExpr(String expr) { + // this is a hack work around for past publication of wrong FHIRPath expressions + if ("(component.empty() and hasMember.empty()) implies (dataAbsentReason or value)".equals(expr)) + return "(component.empty() and hasMember.empty()) implies (dataAbsentReason.exists() or value.exists())"; + if ("isModifier implies isModifierReason.exists()".equals(expr)) + return "(isModifier.exists() and isModifier) implies isModifierReason.exists()"; + if ("(%resource.kind = 'logical' or element.first().path.startsWith(%resource.type)) and (element.tail().not() or element.tail().all(path.startsWith(%resource.differential.element.first().path.replaceMatches('\\\\..*','')&'.')))".equals(expr)) + return "(%resource.kind = 'logical' or element.first().path.startsWith(%resource.type)) and (element.tail().empty() or element.tail().all(path.startsWith(%resource.differential.element.first().path.replaceMatches('\\\\..*','')&'.')))"; + if ("differential.element.all(id) and differential.element.id.trace('ids').isDistinct()".equals(expr)) + return "differential.element.all(id.exists()) and differential.element.id.trace('ids').isDistinct()"; + if ("snapshot.element.all(id) and snapshot.element.id.trace('ids').isDistinct()".equals(expr)) + return "snapshot.element.all(id.exists()) and snapshot.element.id.trace('ids').isDistinct()"; + if ("".equals(expr)) + return ""; + if ("".equals(expr)) + return ""; + if ("".equals(expr)) + return ""; + return expr; + } + + }