Stream: dotnet
Topic: Fhir Path Additional function 'resolve()`
Angus Millar (Sep 19 2018 at 01:48):
Hi Guys, I seem to find that the FHIR Path function named resolve()
does not work or is not supported with the .NET FHIR Path implementation (STU3 or the develop-r4).
If I do use a path with it I get an exception and the following message Unknown symbol 'resolve'
. In FHIR R4 there is a search parameter for the AuditEvent Resource that now uses this resolve() method, like this: AuditEvent.agent.who.where(resolve() is Patient)
.
Only looking to bring this to peoples attention and wondering should I add it as a GitHub issue?
On a side note, I really don't understand how resolve() should work. It appears that when used the FHIR path implementation is somehow intended to retrieve the target, no idea how they can happen?
Brian Postlethwaite (Sep 19 2018 at 02:35):
This is going to be fun.
Brian Postlethwaite (Sep 19 2018 at 02:36):
Yes, resolve is expected to reach out and load that resource into the scope of the navigator.
Brian Postlethwaite (Sep 19 2018 at 02:52):
Oh yes Angus, you can implement the resolve function yourself and add it to the fhirpath symbol table.
Just like I've done for other custom functions in the fhirpath tester.
(and hope that you've registered the fhir extended functions already)
https://github.com/brianpos/FhirPathTester/blob/master/UWP/CustomFluentPathFunctions.cs#L30
Michel Rutten (Sep 19 2018 at 08:37):
Hi @Angus Millar, the Hl7.Fhir.Core library provides implementations for some custom FhirPath functions, including "resolve":
https://github.com/ewoutkramer/fhir-net-api/blob/develop/src/Hl7.Fhir.Core/FhirPath/ElementNavFhirExtensions.cs#L100
Call the static method to initialize FhirPath engine with custom functions:
Hl7.FhirPath.FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions();
Angus Millar (Sep 28 2018 at 04:43):
Thanks, @Michel Rutten this was the gem I needed. It still took a bit of investigation to work out what to do but I feel I now have it working. For others that might be stuck here, I will share what I found.
//Add in the extended FhirPath functions from the fhir.net API as pointed out by Michel in the link above, in the namespace: Hl7.Fhir.FhirPath //Below adds this extended support, it supports some FHIR Path functions (hasValue, resolve, htmlchecks), of which resolve is what I needed. Hl7.FhirPath.FhirPathCompiler.DefaultSymbolTable.AddFhirExtensions(); var oFhirEvaluationContext = new Hl7.Fhir.FhirPath.FhirEvaluationContext(Navigator); //The resolve() function then also needs to be provided an external resolver delegate that performs the resolve //that delegate can be set as below. Here I am providing my own implementation 'IPyroFhirPathResolve.Resolver' oFhirEvaluationContext.Resolver = IPyroFhirPathResolve.Resolver; IEnumerable<IElementNavigator> ResultList = Navigator.Select(Expression, oFhirEvaluationContext); foreach (IElementNavigator oElement in ResultList) { //process what is found by that FHIR path Expression, if any }
My 'Resolver' implementation is simpler than what the full fhir path resolve() requires as I only need to source resource reference urls when the target is a specified resource type, for example, this type of FHIRPath expression AuditEvent.entity.what.where(resolve() is Patient)
, which are now found all though R4 search parameter definitions. To do this I have a 'PyroRequestUri' implementation that parses FHIR references and takes into account, among other things, the server known base URL. So that implementation can work out the target Resource type in any reference, such as https://stu3.test.pyrohealth.net/fhir/Patient/12345
or Patient/12345
or even http://someserver.com/over/here/Patient/12345
where the target in these examples is Patient.
So my Resolver does this and then returns a Hl7.Fhir.ElementModel.IElementNavigator
of which I have a concrete implementation called PyroElementNavigator
. The important property to set is the Type
property to the found Resource name "Patient" in the examples.
This now seems to be working as required for collecting search indexes from resources based on the resolve() function. And I do not take the hit of needing to actually lookup and resolve the reference to an actual resource at an endpoint. Of course in other use cases of resolve() in FHIR path this would not do, another implementation would be required, yet for server resource indexing it seems fine.
Hope this might help someone. Please point out any issues you might see with it.
public Hl7.Fhir.ElementModel.IElementNavigator Resolver(string url) { PyroElementNavigator PyroElementNavigator = new PyroElementNavigator(); var PyroRequestUri = IPyroRequestUriFactory.CreateFhirRequestUri(); if (PyroRequestUri.FhirRequestUri.Parse(url)) { PyroElementNavigator.Name = PyroRequestUri.FhirRequestUri.ResourseName; //This type property is the key property to set for resolve() as it needs to match the comparison //for example 'AuditEvent.agent.who.where(resolve() is Patient)' Patient is Patient PyroElementNavigator.Type = PyroRequestUri.FhirRequestUri.ResourseName; PyroElementNavigator.Value = PyroRequestUri.FhirRequestUri.ResourseName; PyroElementNavigator.Location = url; return PyroElementNavigator; } else { return null; } }
Michel Rutten (Sep 29 2018 at 13:54):
Hi @Angus Millar, thank you for sharing your code! Solid demonstration of how to inject custom functionality into the FhirPath engine, and why we need this.
Last updated: Apr 12 2022 at 19:14 UTC