diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java
index 6e68b7b73..9fea7ad6d 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java
@@ -74,7 +74,7 @@ public class ExpressionNode {
Children, Descendants, MemberOf, Trace, Check, Today, Now, Resolve, Extension, AllFalse, AnyFalse, AllTrue, AnyTrue,
HasValue, OfType, Type, ConvertsToBoolean, ConvertsToInteger, ConvertsToString, ConvertsToDecimal, ConvertsToQuantity, ConvertsToDateTime, ConvertsToTime, ToBoolean, ToInteger, ToString, ToDecimal, ToQuantity, ToDateTime, ToTime, ConformsTo,
// R3 functions
- Encode, Decode, Escape, Trim, Split, Join,
+ Encode, Decode, Escape, Unescape, Trim, Split, Join,
// Local extensions to FHIRPath
HtmlChecks, AliasAs, Alias;
@@ -139,6 +139,7 @@ public class ExpressionNode {
if (name.equals("encode")) return Function.Encode;
if (name.equals("decode")) return Function.Decode;
if (name.equals("escape")) return Function.Escape;
+ if (name.equals("unescape")) return Function.Unescape;
if (name.equals("trim")) return Function.Trim;
if (name.equals("split")) return Function.Split;
if (name.equals("join")) return Function.Join;
@@ -221,6 +222,7 @@ public class ExpressionNode {
case Encode : return "encode";
case Decode : return "decode";
case Escape : return "escape";
+ case Unescape : return "unescape";
case Trim : return "trim";
case Split : return "split";
case Join : return "join";
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
index f24272253..79132ec52 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
@@ -1151,6 +1151,7 @@ public class FHIRPathEngine {
case Encode: return checkParamCount(lexer, location, exp, 1);
case Decode: return checkParamCount(lexer, location, exp, 1);
case Escape: return checkParamCount(lexer, location, exp, 1);
+ case Unescape: return checkParamCount(lexer, location, exp, 1);
case Trim: return checkParamCount(lexer, location, exp, 0);
case Split: return checkParamCount(lexer, location, exp, 1);
case Join: return checkParamCount(lexer, location, exp, 1);
@@ -2661,6 +2662,9 @@ public class FHIRPathEngine {
case Escape:
checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
+ case Unescape:
+ checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
+ return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
case Trim:
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
case Split:
@@ -2846,6 +2850,7 @@ public class FHIRPathEngine {
case Encode : return funcEncode(context, focus, exp);
case Decode : return funcDecode(context, focus, exp);
case Escape : return funcEscape(context, focus, exp);
+ case Unescape : return funcUnescape(context, focus, exp);
case Trim : return funcTrim(context, focus, exp);
case Split : return funcSplit(context, focus, exp);
case Join : return funcJoin(context, focus, exp);
@@ -2958,6 +2963,23 @@ public class FHIRPathEngine {
return result;
}
+ private List funcUnescape(ExecutionContext context, List focus, ExpressionNode exp) {
+ List nl = execute(context, focus, exp.getParameters().get(0), true);
+ String param = nl.get(0).primitiveValue();
+
+ List result = new ArrayList();
+ if (focus.size() == 1) {
+ String cnt = focus.get(0).primitiveValue();
+ if ("html".equals(param)) {
+ result.add(new StringType(Utilities.unescapeXml(cnt)));
+ } else if ("json".equals(param)) {
+ result.add(new StringType(Utilities.unescapeJson(cnt)));
+ }
+ }
+
+ return result;
+ }
+
private List funcTrim(ExecutionContext context, List focus, ExpressionNode exp) {
List result = new ArrayList();
if (focus.size() == 1) {
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java
index 20e79d29a..26421fafe 100644
--- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java
@@ -213,6 +213,9 @@ public class FHIRPathTests {
Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString()));
} else {
Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType()));
+ if (!(v.equals(((PrimitiveType) outcome.get(i)).asStringValue()))) {
+ System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression));
+ }
Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression));
}
}
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
index 4343708b1..48dac02a5 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java
@@ -509,6 +509,55 @@ public class Utilities {
return b.toString();
}
+ public static String unescapeJson(String json) throws FHIRException {
+ if (json == null)
+ return null;
+
+ StringBuilder b = new StringBuilder();
+ int i = 0;
+ while (i < json.length()) {
+ if (json.charAt(i) == '\\') {
+ i++;
+ char ch = json.charAt(i);
+ switch (ch) {
+ case '"':
+ b.append('b');
+ break;
+ case '\\':
+ b.append('\\');
+ break;
+ case '/':
+ b.append('/');
+ break;
+ case 'b':
+ b.append('\b');
+ break;
+ case 'f':
+ b.append('\f');
+ break;
+ case 'n':
+ b.append('\n');
+ break;
+ case 'r':
+ b.append('\r');
+ break;
+ case 't':
+ b.append('\t');
+ break;
+ case 'u':
+ String hex = json.substring(i+1, i+5);
+ b.append((char) Integer.parseInt(hex, 16));
+ break;
+ default:
+ throw new FHIRException("Unknown JSON escape \\"+ch);
+ }
+ } else
+ b.append(json.charAt(i));
+ i++;
+ }
+ return b.toString();
+ }
+
public static boolean isPlural(String word) {
word = word.toLowerCase();