Add support for CCDA .hasTemplateIdOf(canonical)
This commit is contained in:
parent
e56dfb8693
commit
bd1b90b9a5
|
@ -63,6 +63,15 @@ public class TypeManager {
|
|||
}
|
||||
types.add(sd);
|
||||
}
|
||||
if (Utilities.isAbsoluteUrl(type)) {
|
||||
type = sd.getTypeTail();
|
||||
types = typeDefinitions.get(type);
|
||||
if (types == null) {
|
||||
types = new HashSet<>();
|
||||
typeDefinitions.put(type, types);
|
||||
}
|
||||
types.add(sd);
|
||||
}
|
||||
if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
|
||||
primitiveNames.add(sd.getType());
|
||||
} else if (sd.getKind() == StructureDefinitionKind.COMPLEXTYPE) {
|
||||
|
|
|
@ -339,6 +339,18 @@ public abstract class Base implements Serializable, IBase, IElement {
|
|||
return result;
|
||||
}
|
||||
|
||||
public Base getChildValueByName(String name) {
|
||||
Property p = getChildByName(name);
|
||||
if (p != null && p.hasValues()) {
|
||||
if (p.getValues().size() > 1) {
|
||||
throw new Error("Too manye values for "+name+" found");
|
||||
} else {
|
||||
return p.getValues().get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Base[] listChildrenByName(String name, boolean checkValid) throws FHIRException {
|
||||
if (name.equals("*")) {
|
||||
List<Property> children = new ArrayList<Property>();
|
||||
|
|
|
@ -56,7 +56,7 @@ public class ExpressionNode {
|
|||
Encode, Decode, Escape, Unescape, Trim, Split, Join, LowBoundary, HighBoundary, Precision,
|
||||
|
||||
// Local extensions to FHIRPath
|
||||
HtmlChecks1, HtmlChecks2, AliasAs, Alias, Comparable;
|
||||
HtmlChecks1, HtmlChecks2, AliasAs, Alias, Comparable, hasTemplateIdOf;
|
||||
|
||||
public static Function fromCode(String name) {
|
||||
if (name.equals("empty")) return Function.Empty;
|
||||
|
@ -157,6 +157,7 @@ public class ExpressionNode {
|
|||
if (name.equals("lowBoundary")) return Function.LowBoundary;
|
||||
if (name.equals("highBoundary")) return Function.HighBoundary;
|
||||
if (name.equals("precision")) return Function.Precision;
|
||||
if (name.equals("hasTemplateIdOf")) return Function.hasTemplateIdOf;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -260,6 +261,7 @@ public class ExpressionNode {
|
|||
case LowBoundary: return "lowBoundary";
|
||||
case HighBoundary: return "highBoundary";
|
||||
case Precision: return "precision";
|
||||
case hasTemplateIdOf: return "hasTemplateIdOf";
|
||||
default: return "?custom?";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
|
|||
import org.hl7.fhir.r5.model.ExpressionNode.Function;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode.Kind;
|
||||
import org.hl7.fhir.r5.model.ExpressionNode.Operation;
|
||||
import org.hl7.fhir.r5.model.Identifier;
|
||||
import org.hl7.fhir.r5.model.IntegerType;
|
||||
import org.hl7.fhir.r5.model.Property;
|
||||
import org.hl7.fhir.r5.model.Property.PropertyMatcher;
|
||||
|
@ -1436,7 +1437,7 @@ public class FHIRPathEngine {
|
|||
case LowBoundary: return checkParamCount(lexer, location, exp, 0, 1);
|
||||
case HighBoundary: return checkParamCount(lexer, location, exp, 0, 1);
|
||||
case Precision: return checkParamCount(lexer, location, exp, 0);
|
||||
|
||||
case hasTemplateIdOf: return checkParamCount(lexer, location, exp, 1);
|
||||
case Custom: return checkParamCount(lexer, location, exp, details.getMinParameters(), details.getMaxParameters());
|
||||
}
|
||||
return false;
|
||||
|
@ -3141,7 +3142,7 @@ public class FHIRPathEngine {
|
|||
}
|
||||
} else {
|
||||
while (sd != null) {
|
||||
if (sd.getType().equals(exp.getName())) {
|
||||
if (sd.getType().equals(exp.getName()) || sd.getTypeTail().equals(exp.getName())) {
|
||||
result.add(item);
|
||||
break;
|
||||
}
|
||||
|
@ -3627,7 +3628,10 @@ public class FHIRPathEngine {
|
|||
checkContextContinuous(focus, exp.getFunction().toCode(), exp);
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer);
|
||||
}
|
||||
|
||||
case hasTemplateIdOf: {
|
||||
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
|
||||
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
|
||||
}
|
||||
case Custom : {
|
||||
return hostServices.checkFunction(this, context.appInfo,exp.getName(), focus, paramTypes);
|
||||
}
|
||||
|
@ -3862,6 +3866,7 @@ public class FHIRPathEngine {
|
|||
case LowBoundary : return funcLowBoundary(context, focus, exp);
|
||||
case HighBoundary : return funcHighBoundary(context, focus, exp);
|
||||
case Precision : return funcPrecision(context, focus, exp);
|
||||
case hasTemplateIdOf: return funcHasTemplateIdOf(context, focus, exp);
|
||||
|
||||
|
||||
case Custom: {
|
||||
|
@ -3890,6 +3895,53 @@ public class FHIRPathEngine {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Base> funcHasTemplateIdOf(ExecutionContext context, List<Base> focus, ExpressionNode exp) {
|
||||
List<Base> result = new ArrayList<Base>();
|
||||
List<Base> swb = execute(context, focus, exp.getParameters().get(0), true);
|
||||
String sw = convertToString(swb);
|
||||
|
||||
StructureDefinition sd = this.worker.fetchResource(StructureDefinition.class, sw);
|
||||
if (focus.size() == 1 && sd != null) {
|
||||
boolean found = false;
|
||||
for (Identifier id : sd.getIdentifier()) {
|
||||
if (id.getValue().startsWith("urn:hl7ii:")) {
|
||||
String[] p = id.getValue().split("\\:");
|
||||
if (p.length == 4) {
|
||||
found = found || hasTemplateId(focus.get(0), p[2], p[3]);
|
||||
}
|
||||
} else if (id.getValue().startsWith("urn:oid:")) {
|
||||
found = found || hasTemplateId(focus.get(0), id.getValue().substring(8));
|
||||
}
|
||||
}
|
||||
result.add(new BooleanType(found));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean hasTemplateId(Base base, String rv) {
|
||||
List<Base> templateIds = base.listChildrenByName("templateId");
|
||||
for (Base templateId : templateIds) {
|
||||
Base root = templateId.getChildValueByName("root");
|
||||
Base extension = templateId.getChildValueByName("extension");
|
||||
if (extension == null && root != null && rv.equals(root.primitiveValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasTemplateId(Base base, String rv, String ev) {
|
||||
List<Base> templateIds = base.listChildrenByName("templateId");
|
||||
for (Base templateId : templateIds) {
|
||||
Base root = templateId.getChildValueByName("root");
|
||||
Base extension = templateId.getChildValueByName("extension");
|
||||
if (extension != null && ev.equals(extension.primitiveValue()) && root != null && rv.equals(root.primitiveValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<Base> funcSqrt(ExecutionContext context, List<Base> focus, ExpressionNode expr) {
|
||||
if (focus.size() != 1) {
|
||||
throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "sqrt", focus.size());
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
|||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.FunctionDetails;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
@ -102,11 +104,20 @@ public class FHIRPathTests {
|
|||
}
|
||||
|
||||
private static FHIRPathEngine fp;
|
||||
private final Map<String, Resource> resources = new HashMap<String, Resource>();
|
||||
private final Map<String, Base> resources = new HashMap<String, Base>();
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
fp = new FHIRPathEngine(TestingUtilities.getSharedWorkerContext());
|
||||
public static void setUp() throws FileNotFoundException, FHIRException, IOException {
|
||||
if (!TestingUtilities.getSharedWorkerContext().hasPackage("hl7.cda.us.ccda", null)) {
|
||||
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true);
|
||||
NpmPackage npm = pcm.loadPackage("hl7.cda.uv.core");
|
||||
TestingUtilities.getSharedWorkerContext().loadFromPackage(npm, null);
|
||||
npm = pcm.loadPackage("hl7.cda.us.ccda");
|
||||
TestingUtilities.getSharedWorkerContext().loadFromPackage(npm, null);
|
||||
}
|
||||
if (fp == null) {
|
||||
fp = new FHIRPathEngine(TestingUtilities.getSharedWorkerContext());
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<Arguments> data() throws ParserConfigurationException, SAXException, IOException {
|
||||
|
@ -168,7 +179,7 @@ public class FHIRPathTests {
|
|||
fail = TestResultType.EXECUTION;
|
||||
};
|
||||
fp.setAllowPolymorphicNames("lenient/polymorphics".equals(test.getAttribute("mode")));
|
||||
Resource res = null;
|
||||
Base res = null;
|
||||
|
||||
List<Base> outcome = new ArrayList<Base>();
|
||||
|
||||
|
@ -187,7 +198,9 @@ public class FHIRPathTests {
|
|||
if (!Utilities.noString(input)) {
|
||||
res = resources.get(input);
|
||||
if (res == null) {
|
||||
if (input.endsWith(".json")) {
|
||||
if ("cda".equals(test.getAttribute("mode"))) {
|
||||
res = Manager.makeParser(fp.getWorker(), FhirFormat.XML).parseSingle(TestingUtilities.loadTestResourceStream("r5", input), null);
|
||||
} else if (input.endsWith(".json")) {
|
||||
res = new JsonParser().parse(TestingUtilities.loadTestResourceStream("r5", input));
|
||||
} else {
|
||||
res = new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", input));
|
||||
|
@ -200,7 +213,7 @@ public class FHIRPathTests {
|
|||
if (Utilities.noString(input)) {
|
||||
fp.check(null, null, node);
|
||||
} else {
|
||||
fp.check(res, res.getResourceType().toString(), res.getResourceType().toString(), node);
|
||||
fp.check(res, res.fhirType(), res.fhirType(), node);
|
||||
}
|
||||
Assertions.assertTrue(fail != TestResultType.SEMANTICS, String.format("Expected exception didn't occur checking %s", expression));
|
||||
} catch (Exception e) {
|
||||
|
|
Loading…
Reference in New Issue