ANF XSLT Transformation
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"/>
<text>Does patient have a Comorbidity?</text>
<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"/>
<text>Does patient have Cardial Comorbidity?</text>
<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"/>
<text>Does patient have Vascular Comorbidity?</text>
<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:variable name="questionNarrative" select="./text"/>
<xsl:for-each select="document('questionnaireResponse.xml')//item">
<xsl:if test="./linkId/@value = $questionId">
<statement>
<narrative>
<xsl:value-of select="$questionNarrative"/>
</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>