Summary
Below highlights a working example of transforming both FHIR Questionnaire Resource and a corresponding Questionnaire Response Resource into a simple notional ANF logical representation. This is achieved utilizing the Saxon XSLT engine (https://www.saxonica.com/documentation/index.html#!using-xsl/commandline) against version 3.0 XSLT and version 3.1 XPath.
Example FHIR Questionnaire Resource
<?xml version="1.0" encoding="UTF-8"?> <Questionnaire xmlns="http://hl7.org/fhir"> <id value="3141"/> <text> <status value="generated"/> <div xmlns="http://www.w3.org/1999/xhtml"> <pre>1.Comorbidity? 1.1 Cardial Comorbidity 1.1.1 Angina? 1.1.2 MI? 1.2 Vascular Comorbidity? ... Histopathology Abdominal pT category? ... </pre> </div> </text> <url value="http://hl7.org/fhir/Questionnaire/3141"/> <title value="Cancer Quality Forum Questionnaire 2012"/> <status value="draft"/> <subjectType value="Patient"/> <date value="2012-01"/> <item> <linkId value="1"/> <code> <system value="http://example.org/system/code/sections"/> <code value="COMORBIDITY"/> </code> <type value="group"/> <item> <linkId value="1.1"/> <code> <system value="http://example.org/system/code/questions"/> <code value="COMORB"/> </code> <prefix value="1"/> <type value="choice"/> <answerValueSet value="http://hl7.org/fhir/ValueSet/yesnodontknow"/> <item> <linkId value="1.1.1"/> <code> <system value="http://example.org/system/code/sections"/> <code value="CARDIAL"/> </code> <type value="group"/> <enableWhen> <question value="1.1"/> <operator value="="/> <answerCoding> <system value="http://terminology.hl7.org/CodeSystem/v2-0136"/> <code value="Y"/> </answerCoding> </enableWhen> <item> <linkId value="1.1.1.1"/> <code> <system value="http://example.org/system/code/questions"/> <code value="COMORBCAR"/> </code> <prefix value="1.1"/> <type value="choice"/> <answerValueSet value="http://hl7.org/fhir/ValueSet/yesnodontknow"/> <item> <linkId value="1.1.1.1.1"/> <code> <system value="http://example.org/system/code/questions"/> <code value="COMCAR00"/> <display value="Angina Pectoris"/> </code> <code> <system value="http://snomed.info/sct"/> <code value="194828000"/> <display value="Angina (disorder)"/> </code> <prefix value="1.1.1"/> <type value="choice"/> <answerValueSet value="http://hl7.org/fhir/ValueSet/yesnodontknow"/> </item> <item> <linkId value="1.1.1.1.2"/> <code> <system value="http://snomed.info/sct"/> <code value="22298006"/> <display value="Myocardial infarction (disorder)"/> </code> <prefix value="1.1.2"/> <type value="choice"/> <answerValueSet value="http://hl7.org/fhir/ValueSet/yesnodontknow"/> </item> </item> <item> <linkId value="1.1.1.2"/> <code> <system value="http://example.org/system/code/questions"/> <code value="COMORBVAS"/> </code> <prefix value="1.2"/> <type value="choice"/> <answerValueSet value="http://hl7.org/fhir/ValueSet/yesnodontknow"/> </item> </item> </item> </item> <item> <linkId value="2"/> <code> <system value="http://example.org/system/code/sections"/> <code value="HISTOPATHOLOGY"/> </code> <type value="group"/> <item> <linkId value="2.1"/> <code> <system value="http://example.org/system/code/sections"/> <code value="ABDOMINAL"/> </code> <type value="group"/> <item> <linkId value="2.1.2"/> <code> <system value="http://example.org/system/code/questions"/> <code value="STADPT"/> <display value="pT category"/> </code> <type value="choice"/> </item> </item> </item> </Questionnaire>
Example FHIR Questionnaire Response Resource
<?xml version="1.0" encoding="UTF-8"?> <QuestionnaireResponse xmlns="http://hl7.org/fhir"> <id value="3141" /> <text> <status value="generated" /> <div xmlns="http://www.w3.org/1999/xhtml"> <pre> Comorbidity? YES Cardial Comorbidity? YES Angina? YES MI? NO Vascular Comorbidity? (no answers) ... Histopathology Abdominal pT category: 1a ... </pre> </div> </text> <contained> <Patient> <id value="patsub" /> <identifier> <system value="http://cancer.questionnaire.org/systems/id/patientnr" /> <value value="A34442332" /> </identifier> <identifier> <type> <text value="Dutch BSN" /> </type> <system value="urn:oid:2.16.840.1.113883.2.4.6.3" /> <value value="188912345" /> </identifier> <gender value="male" /> <birthDate value="1972-11-30" /> </Patient> </contained> <contained> <ServiceRequest> <id value="order" /> <status value="unknown" /> <intent value="order" /> <subject> <reference value="#patsub" /> </subject> <requester> <reference value="Practitioner/example" /> </requester> </ServiceRequest> </contained> <contained> <Practitioner> <id value="questauth" /> <identifier> <type> <text value="AUMC, Den Helder" /> </type> <system value="http://cancer.questionnaire.org/systems/id/org" /> <value value="AUMC" /> </identifier> </Practitioner> </contained> <!-- TODO: decide how to do this <contained> <Observation> <id value="obs.pt-category"/> <status value="final"/> <code> <coding> <system value="http://snomed.info/sct"/> <code value="53786006"/> <display value="pT1 category"/> </coding> </code> <subject> <reference value="#patsub"/> </subject> <performer> <reference value="#questauth"/> </performer> <valueCodeableConcept> <coding> <system value="http://snomed.info/sct"/> <code value="443357004"/> <display value="pT1a category"/> </coding> </valueCodeableConcept> </Observation> </contained> --> <identifier> <system value="http://example.org/fhir/NamingSystem/questionnaire-ids" /> <value value="Q12349876" /> </identifier> <basedOn> <reference value="#order" /> </basedOn> <partOf> <reference value="Procedure/f201" /> </partOf> <status value="completed" /> <subject> <reference value="#patsub" /> </subject> <encounter> <reference value="Encounter/example" /> </encounter> <authored value="2013-02-19T14:15:00-05:00" /> <author> <reference value="#questauth" /> </author> <item> <!-- COMORBIDITY --> <!-- First main section of the form, questions about comorbidity --> <!-- section contains one question: whether there is comorbidity --> <linkId value="1" /> <item> <linkId value="1.1" /> <answer> <valueCoding> <system value="http://cancer.questionnaire.org/system/code/yesno" /> <code value="1" /> <display value="Yes" /> </valueCoding> <item> <!-- COMORBIDITY/CARDIAL --> <!-- Subsection about specific comorbidity: cardial --> <linkId value="1.1.1" /> <item> <linkId value="1.1.1.1" /> <answer> <valueCoding> <system value="http://cancer.questionnaire.org/system/code/yesno" /> <code value="0" /> </valueCoding> </answer> </item> <item> <!-- This answer carries both the questionnaire-specific name and an equivalent SNOMED CT code --> <linkId value="1.1.1.2" /> <answer> <valueCoding> <system value="http://cancer.questionnaire.org/system/code/yesno" /> <code value="3" /> </valueCoding> </answer> </item> <item> <linkId value="1.1.1.3" /> <answer> <valueCoding> <system value="http://cancer.questionnaire.org/system/code/yesno" /> <code value="0" /> </valueCoding> </answer> </item> </item> </answer> </item> </item> <!-- HISTOPATHOLOGY --> <!-- TODO: decide how to do this <item> <item> <item> <dataResource> <reference value="#obs.pt-category"/> </dataResource> </item> </item> </item> --> </QuestionnaireResponse>
Notional Logical ANF XSTL Transformation
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://hl7.org/fhir"> <xsl:output indent="yes" omit-xml-declaration="no"/> <xsl:variable name="presentRange">(0,INF)</xsl:variable> <xsl:variable name="absentRange">[0,0]</xsl:variable> <xsl:variable name="indeterminateRange">[0,INF)</xsl:variable> <xsl:template match="/"> <anf> <xsl:for-each select="//item"> <xsl:if test="./type/@value = 'choice'"> <xsl:variable name="questionId" select="./linkId/@value"/> <xsl:variable name="questionTopic" select="./code/code/@value"/> <xsl:for-each select="document('questionnaireResponse.xml')//item"> <xsl:if test="./linkId/@value = $questionId"> <statement> <narrative> <xsl:value-of select="$questionId"/> </narrative> <topic> <xsl:value-of select="$questionTopic"/> </topic> <circumstance type="performance"> <status>Complete</status> <result> <xsl:choose> <xsl:when test="./answer/valueCoding/code/@value = 1"> <xsl:value-of select="$presentRange"/> </xsl:when> <xsl:when test="./answer/valueCoding/code/@value = 0"> <xsl:value-of select="$absentRange"/> </xsl:when> <xsl:when test="./answer/valueCoding/code/@value = 3"> <xsl:value-of select="$indeterminateRange"/> </xsl:when> </xsl:choose> </result> </circumstance> </statement> </xsl:if> </xsl:for-each> </xsl:if> </xsl:for-each> </anf> </xsl:template> </xsl:stylesheet>
Notional Logical ANF Output
<?xml version="1.0" encoding="UTF-8"?> <anf> <statement> <narrative>1.1</narrative> <topic>COMORB</topic> <circumstance type="performance"> <status>Complete</status> <result>(0,INF)</result> </circumstance> </statement> <statement> <narrative>1.1.1.1</narrative> <topic>COMORBCAR</topic> <circumstance type="performance"> <status>Complete</status> <result>[0,0]</result> </circumstance> </statement> <statement> <narrative>1.1.1.2</narrative> <topic>COMORBVAS</topic> <circumstance type="performance"> <status>Complete</status> <result>[0,INF)</result> </circumstance> </statement> </anf>
0 Comments