Open ewoutkramer opened 2 months ago
Here is an analysis of the forms of XPath queries encountered in USCore and QICore:
(from USCore)
<any resource name>
'%value.value'
'FHIRHelpers.ToInterval(%value)' // and many other functions from FHIRHelpers instead of ToInterval()
'FHIRHelpers.ToCode(%parent.extension[url='ombCategory'].value)'
'%parent.extension[url='text'].value.value'
'%parent.extension[url='http://hl7.org/fhir/us/core/StructureDefinition/us-core-race']'
'%parent.extension[url='http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex'].value.value'
'FHIRHelpers.ToConcept(%parent.category[coding.system='http://terminology.hl7.org/CodeSystem/observation-category',coding.code='vital-signs'])'
'FHIRHelpers.ToCode(%parent.code.coding[system='http://loinc.org',code='2708-6'])'
(from QICore)
%value.value
FHIRHelpers.ToInterval(%value)
FHIRHelpers.ToQuantity(%parent.extension[url='http://hl7.org/fhir/StructureDefinition/allergyintolerance-resolutionAge'].value)
FHIRHelpers.ToQuantity(%parent.reaction.extension[url='http://hl7.org/fhir/StructureDefinition/allergyintolerance-duration'].value)
%parent.extension[url='http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-recorded'].value.value
System.Concept:FHIRHelpers.ToConcept(%value);System.ValueSet:FHIRHelpers.ToValueSet(%parent.topic.extension[url='http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-notDoneValueSet'].value.value)
System.Concept:FHIRHelpers.ToConcept(%value);System.ValueSet:FHIRHelpers.ToValueSet(%parent.code[x].extension[url='http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-notDoneValueSet'].value.value)
%parent.extension[url='null']
System.Concept:FHIRHelpers.ToConcept(%value);System.ValueSet:FHIRHelpers.ToValueSet(%parent.vaccineCode.extension[url='http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-notDoneValueSet'].value.value)
System.Concept:FHIRHelpers.ToConcept(%value);System.ValueSet:FHIRHelpers.ToValueSet(%parent.medication[x].extension[url='http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-notDoneValueSet'].value.value)
As can be glanced from the above, the XPath language needs at minimum a feature to recognize qualified identifiers (FHIRHelpers.ToInterval
), placeholders (%value
, %parent
), path navigation (both relative and based on placeholders!) (%parent.code.coding
, url
), selection with multiple criteria ([coding.system='something', coding.code='vital signs']
)
Also, the expression can actually be a list of XPath statements, selected based on the static(?) type of the expression.
This probably needs a specific sub-language parser for which we could use superpower or something comparably light.
And we need to study the CQL that is being generated for it by the Java stack. I.e. a simple extension looks like:
<operand xsi:type="Query">
<source alias="$this">
<expression path="extension" xsi:type="Property">
<source localId="33" locator="15:7-15:15" resultTypeName="fhir:Patient" name="Patient" xsi:type="ExpressionRef"/>
</expression>
</source>
<where xsi:type="Equal">
<operand name="ToString" libraryName="FHIRHelpers" xsi:type="FunctionRef">
<operand path="url" scope="$this" xsi:type="Property"/>
</operand>
<operand valueType="t:String" value="http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex" xsi:type="Literal"/>
</where>
<return distinct="false">
<expression path="value.value" xsi:type="Property">
<source name="$this" xsi:type="AliasRef"/>
</expression>
</return>
</operand>
Here's a bit of profile-informed CQL to get you started:
library TestRetrieve version '1.0.1'
using USCore version '3.1.1'
include FHIRHelpers version '4.0.1' called FHIRHelpers
valueset "Female Administrative Sex": '2.16.840.1.113883.3.560.100.2'
parameter MeasurementPeriod default Interval[DateTime(2013, 1, 1, 0, 0, 0, 0), DateTime(2014, 1, 1, 0, 0, 0, 0))
context Patient
define "InDemographic":
AgeInYearsAt(start of MeasurementPeriod) >= 16 and AgeInYearsAt(start of MeasurementPeriod) < 24
and "Patient"."birthsex" in "Female Administrative Sex"
define "Bla":
["observation-bp"] O where O.SystolicBP.value < 140 'mm[Hg]'
Complexity may arise from which slicing is supported, e.g. the slices in the above (systolic) are simple fix-value slices on coding.code and system. But may there be slices on valuesets? We probably don't need to support everything now, as long as we keep an eye on new updates to the most common (QICore, USCore) modelinfos....
It is possible to specify another model than FHIR, i.e. "QICore", in which case the modelinfo introduces first-class members into the resources for extensions and slices.
E.g..
Introduces a direct reference to the
birthsex
extension, and theSystolicBP
slice.All of this information is available in the profile-specific modelinfos, available from here: https://github.com/cqframework/clinical_quality_language/tree/master/Src/java/quick/src/main/resources/org/hl7/fhir
The syntax in modelinfo is actually pretty generic, elements are augmented with a
target
attribute that specifies a (XPath?) query to replace the element and map to the target model.I.e. the
birthsex
extension looks like this:Note that this is not just a search/replace, as the syntax describing the replacement is not CQL itself, but XPath.