The Health Level 7 (HL7) Clinical Document Architecture (CDA) is based on the same HL7 version 3 Reference Information Model used to develop interactions for HL7 v3 messaging. Whereas HL7 messaging represents individual healthcare interactions (such as queries, responses, and notifications), an HL7 CDA document is a single, persistent document that represents a patient visit, a continuity-of-care document, and the like. To make the entries in a CDA readable by people, each has a text description in addition to any machine-readable content, as in Listing 1. HL7 v3 messages are, strictly speaking, intended for transmission over a wire (for example, as part of a client-server interaction or server-server data distribution); because they are also intended for human readability, HL7 CDA documents can be transferred by other means, such as email.
Listing 1. An observation entry in CDA: Penicillin allergy
<component>
<section>
<code code="10155-0" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
<title>Allergies and Adverse Reactions</title>
<text>
<list>
<item>Penicillin - Hives</item>
</list>
</text>
<entry>
<observation classCode="OBS" moodCode="EVN">
<code xsi:type="CD" code="247472004" codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED CT" displayName="Hives"/>
<statusCode code="completed"/>
<entryRelationship typeCode="MFST">
<observation classCode="OBS" moodCode="EVN">
<code xsi:type="CD" code="91936005"
codeSystem="2.16.840.1.113883.6.96"
codeSystemName="SNOMED CT"
displayName="Allergy to penicillin"/>
<statusCode code="completed"/>
</observation>
</entryRelationship>
</observation>
</entry>
</section>
</component>
|
The Saxon parser has supported XSLT 2.0 transformations on the server side for several years now. Recently, at the 2011 XML Prague conference, Dr. Michael Kay, who wrote the original Saxon parser, introduced an alpha release of Saxon Client Edition (Saxon-CE), which allows XSLT 2.0 transformations to be run directly from the web client application (in the browser). Saxon-CE uses JavaScript to run on any modern browser, which has been an ongoing issue with XSL on the client side: Historically, XSL support has not been consistently implemented by the different browsers. Because it uses JavaScript as a run-time engine, Saxon-CE resolves this issue.
In addition, XSLT 2.0 provides several features that were not supported in the original XSLT 1.0 specification, such as support for multiple documents and stronger data typing. With Saxon-CE, these features are now supported in the client, and, as this article demonstrates, some of these features are ideally suited for use in client application views—in particular, client-side support for multiple documents.
To develop the CDA Viewer application described in this article, I used the Unite web server that comes packaged with the latest Opera release. You could use any application server you prefer. Because I am describing how to develop a client application view, I don't describe how the CDA document is persisted or distributed. To test my application view, I simply publish a sample CDA as a URL directly through the web server (alternatively, you might persist these in an XML database such as IBM® DB2® pureXML). Similarly, my XSL transforms are published as URLs.
The Saxon-CE alpha release is currently available for download from the Saxonica website (see Resources for a link). This alpha release is not intended for production applications at this point; however, based on the success of the original Saxon parser, I have no doubt that the Client Edition will also quickly become an industry standard, especially if it meets with positive feedback from early adopters.
The alpha release comes with comprehensive release notes. You can copy the JavaScript files contained in the unzipped release folder to your application server, as you would any other .js scripts. You should also take some time to download the sample applications. The JavaScript consists of a single .nocache.js file along with a number of minified .js files—one for each major browser. These files contain the actual parser code; the .nocache.js file detects which browser is in use and then calls out to the appropriate .js script. The sample applications consist of an XSL transform file, some XML data, and an HTML file that calls the Saxon-CE JavaScript to run the transform. The CDA Viewer application that I built follows the same pattern, although I broke my transformation layer into three files for readability (see Download). On my web server, I have one folder for each of the sample applications and then one for my CDA application.
Exploring the features in XSLT 2.0
Many features were introduced in the XSLT 2.0 specification—features like
function definitions, multiple result documents, sequences and temporary trees,
stronger typing, and text parsing. This article highlights support for multiple
result documents. On the server side, using multiple result documents means creating
multiple documents on the server, so that you can create an XHTML home page that
references several other result pages, all generated on the server. In the context of
server-side transformation, using multiple result documents means just that: multiple
documents. Listing 2 demonstrates this approach. When you generate
multiple documents on the client side using Saxon-CE, the generated content is
actually targeted to different screen areas of your client application (typically,
div elements in the HTML page).
Listing 2. Multiple result documents (on the server)
<xsl:for-each select="section">
<xsl:result-document href="{@id}.html">
<xsl:apply-templates select="." mode="html" />
</xsl:result-document>
</xsl:for-each>
|
Transforming the clinical document
I organized my XSL transformations into three files (see Download):
- cda.xsl. Contains the basic transformation to display the human-readable document
- cda-machine-readable.xsl. Contains a customizable layer that currently displays the machine-readable details of the document in a tidier fashion
- cda-dom-interaction.xsl. Contains templates that handle interactions with the DOM of the HTML page, such as click events
In addition, there are a CSS file and the HTML page itself.
The CSS is straightforward. The HTML page is likewise straightforward, containing a
number of div elements for the different screen areas
of the CDA Viewer, each of which can be positioned by an ID in the CSS. My plan is
to load the entire CDA and transform it, then allow interactive access through
the DOM so that I have a div element called
div-cache, which I have hidden at the bottom of the
viewer. This cache contains a copy of each of the entries recorded in the CDA. You
can scroll down and see this text, or you can make this element hidden by marking
it style="visibility:hidden;inline:none".
The code in Listing 3 triggers the transformation process.
As you can see, <script> tags call out
to first the Saxon-CE JavaScript and then the XSL transformation stylesheet,
targeting the CDA document.
Listing 3. Invoking Saxon-CE from the HTML page
<script type="text/javascript" language="javascript" src="../Saxonce.nocache.js"></script>
<script type="application/xslt+xml" language="xslt2.0" src="cda.xsl"
input="SampleCDADocument.xml"></script>
|
Displaying the CDA Viewer's table of contents
In Listing 3, the main transformation first
creates a simplified header for the CDA Viewer by extracting some of the
information from the CDA wrapper. Already, you can see
xsl:result-document in action. In
Listing 4, notice how the <div>
tag is targeted by its #creation ID.
method="ixsl:replace-content" is Saxon-CE shorthand
for "in the interactive XSL, replace the content." You'll see an example in a
moment of appending content. Notice that when you deal directly with
the CDA, you need to use the hl7: namespace
whenever you refer to an element in the CDA. You will see later that this isn't
necessary when you deal with templates that refer to the DOM. This process can
be tricky and is one reason why I separated my templates into several XSL style
sheets.
Listing 4. Replacing content with xsl:result-document
<xsl:result-document href="#creation" method="ixsl:replace-content">
<div>
<xsl:value-of>
<xsl:value-of select="hl7:ClinicalDocument/hl7:title"/>:
<xsl:value-of
select="hl7:ClinicalDocument/hl7:recordTarget/hl7:patientRole/hl7:patient"/>
</xsl:value-of>
</div>
</xsl:result-document>
|
In the next piece of code from the same XSL file (see Listing 5),
you can see how the table of contents for the CDA Viewer is generated from
the sections in the CDA document. Take a look at the sample files provided for
details on how the table of contents is formatted. A similar approach is used to
cache the clinical entry data from the CDA. In both cases, you can see how the
results are appended to the existing contents of the targeted
<div> element each time the template is applied.
Listing 5. Appending content with xsl:result-document
<xsl:result-document href="#notes" method="ixsl:append-content">
<xsl:apply-templates select="//hl7:component/hl7:section" mode="notes"/>
</xsl:result-document>
<xsl:result-document href="#div-cache" method="ixsl:append-content">
<xsl:apply-templates select="//hl7:component/hl7:section" mode="cache"/>
</xsl:result-document>
|
Figure 1 shows the basic CDA Viewer and table of contents.
Figure 1. The CDA Viewer table of contents
Generated IDs are used to connect links in the table of contents to the cached CDA entries. Listing 6 provides an excerpt from the template used to create an entry in the table of contents.
Listing 6. Linking to the cached CDA entry
<a class="notes-section">
<xsl:attribute name="id"><xsl:value-of select="generate-id(.)"/></xsl:attribute>
<xsl:value-of select="hl7:title"/>
</a>
|
In Listing 7, notice how the mode="ixsl:onclick"
attribute on the template is used to tell Saxon-CE to apply this template
to handle a click event. This is no different than any other JavaScript click
event: It is simply handled by Saxon-CE and the XSL stylesheet. Note that
whenever the parser handles a click event like this, the context shifts from
the original XML document to the DOM of the HTML page, which is why I separated
these templates into a transformation stylesheet called cda-dom-interaction.xsl.
The template itself displays the text of the CDA entry, extracted from the
cache created earlier using the ID associated with the original click event
(the ID of the original anchor link). This text replaces the content of the
note-detail result document
div element. The template then applies any
applicable downstream templates to deal with machine-readable content in
the CDA entry.
Listing 7. Handling a click event from the table of contents
<xsl:template match="a[@class='notes-section']" mode="ixsl:onclick">
<xsl:variable name="div-id" select="@id"/>
<xsl:variable name="selected-section"
select="//div[@id='div-cache']/div[@id=$div-id]/section"/>
<xsl:result-document href="#note-detail" method="ixsl:replace-content">
<h2><xsl:value-of select="$selected-section/title/text()"/>
(<xsl:value-of select="$div-id"/>)</h2>
<div><xsl:value-of select="$selected-section/text"/></div>
<h2>Machine-readable Content</h2>
<xsl:apply-templates select="$selected-section" mode="mach-read">
<xsl:with-param name="a" select="."/>
</xsl:apply-templates>
</xsl:result-document>
</xsl:template>
|
To keep the machine-readable and human-readable concerns separate, I created and included a third transformation stylesheet called cda-machine-readable.xsl. Keeping these templates separate has the advantage that this third stylesheet can be extended or completely replaced to use a more sophisticated stylesheet to handling the machine-readable information in the CDA. You might want to do this, for instance, to provide fancier tables or graphic representations of data or to withhold certain types of entries. Alternatively, you might want to go deep and load another XML document, perhaps from a metadata repository, and expand on some of the codes within the machine-readable data or categorize them using common code systems. Keeping the templates for transforming machine-readable entries is good programming practice, as is separation of concerns in general. I have found this practice essential when dealing with large-scale transformations or transformations I expect to grow.
Displaying machine-readable clinical entries
My minimalist machine-readable transformation stylesheet contains a single
template that identifies a number of known entry types (Observation,
Substance Administration, Procedure, and Act events) and styles them using
bulleted lists and tables. I made no attempt to do anything too fancy here,
but it is a useful exercise to look at how a simple template can provide a
substantial return in style and organization. Also notice how in
Listing 8 the originating anchor link is passed to the
template using a parameter. This step is not necessary to display the machine-readable
data; rather, the link is passed through this template and cached for later use
in a hidden div element at the bottom of the entry
detail. This link information will subsequently be used to build what I am calling
a pin area. For the sake of brevity, I omitted all but the
xsl:when for Observation in the
xsl:choose.
Listing 8. Templating machine-readable CDA entries
<xsl:template match="section" mode="mach-read">
<xsl:param name="a"/>
<div id="mach-read">
<xsl:choose>
<xsl:when test="entry/observation">
<h3>Observations</h3>
<ul>
<xsl:for-each select="entry/observation">
<li><a>
<xsl:value-of select="text"/>
<xsl:value-of select="code/@displayName"/>
<xsl:for-each select="value">
(<xsl:value-of><xsl:value-of select="@value"/>
<xsl:value-of select="@unit"/></xsl:value-of>)
</xsl:for-each>
</a></li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>(no match)</xsl:otherwise>
</xsl:choose>
<div class="xref" style="visibility:hidden;inline:none">
<xsl:copy-of select="$a"/>
</div>
</div>
</xsl:template>
|
Notice that because this template is applied to a copy of the original CDA data
that was cached in the DOM, the hl7: is not
required for elements like entry,
code, and observation. If
you want, you can add this namespace to the cached CDA entries, but there is
little benefit for doing so because no further serialization is performed. If there
were any ambiguity between HL7 CDA elements and other elements on the page,
doing so would be pragmatic.
Figure 2 shows the CDA Viewer displaying an observation event representing allergies and adverse reactions.
Figure 2. Observation events, such as allergies and adverse reactions
Developing a new design pattern: The pin area
The pin area is a design pattern that emerged during development of these transformations, inspired by the way Saxon-CE implements XSLT 2.0 result documents. As previously described, generated content either can be appended to a screen area or can replace existing content. Typically, you will want to replace existing content; however, when you are applying a template repeatedly, you want to append content. If you apply several templates to the same target screen area, you can create a collection that resembles a bookmark: You can interactively add to this collection over time without removing any of the existing content in the screen area.
In the sample code in Listing 9, look at the template to pin anchor links. Granted, this is a sample application, but the idea here is intriguing. When you click a link in the Viewer's table of contents, the click event is handled by displaying the contents of that section of the CDA. When you click any other link, however, a simple anchor template handles the link event and copies the contents of the link to the pin area. The result is that you can use the Viewer to sift through the contents of the clinical document and "pin" entries for later reference.
Listing 9. Templating the pin area
<xsl:template match="a" mode="ixsl:onclick">
<xsl:variable name="div-mach-read" select="ancestor::div[@id='mach-read']"/>
<xsl:result-document href="#pin" method="ixsl:append-content">
<div>
<xsl:attribute name="title"><xsl:value-of select="$div-mach-read/h3"/>
- <xsl:value-of select="text()"/></xsl:attribute>
<xsl:copy-of select="$div-mach-read/div[@class='xref']/a"/> -
<xsl:value-of select="text()"/>
</div>
</xsl:result-document>
</xsl:template>
|
Figure 3 shows the pin area in use.
Figure 3. The pin area of the CDA Viewer
The benefits of this design pattern are, of course, increased if you can do something useful with the pinned entries; however, that discussion goes beyond the scope of this article. A potential use case might involve a plug-in to an email browser that allowed a patient to view a CDA received from his or her practitioner, pin some entries, and then enclose them in an email response. Because of the way they handle information declaratively, Saxon-CE and XSLT 2.0 will no doubt prove to be useful tools in developing these applications.
CDA documents are persistent and as a result are often quite large. Although they are intended to be human-readable, CDA documents also contain a wealth of machine-readable information, which can be made more manageable by transformation into an expanded client view. I'm sure that with future releases, Saxon-CE will prove to be an essential tool for doing just this because it can run on any modern browser and because it offers client-side XSLT 2.0 features such as multiple result document support. I fully expect this technology to become indispensable to developers of rich healthcare applications.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample CDA application | cda_sample.zip | 16KB | HTTP |
Information about download methods
Learn
- XML for Data: XSLT 2.0: An early look" (Kevin Williams, developerWorks, July 2002): Review many of the features of XSLT 2.0 and code samples that show just how useful this XML styling language can be.
- Compiling Saxon using GWT (Dr. Michael Kay, Saxon diaries, November 2010): In this blog entry, learn how the Saxon parser was ported from Java™ to JavaScript using Google Web Toolkit.
- The HL7 Clinical Document Architecture: Learn more about HL7 CDA in the Journal of the American Medical Informatics Association.
- HL7 version 3: Message or CDA Document?: Learn more about the differences between HL7 v3 messaging and CDA in this informative article on Ringholm.
- More articles by this author (Piers Michael Hollott,
developerWorks, November 2010-current): Read articles about DITA and other technologies.
- New to XML? Get the resources you need to learn XML.
- XML area on developerWorks: Find the resources you need to advance your skills in the XML arena, including DTDs, schemas, and XSLT. See the XML technical library for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- developerWorks on Twitter: Join today to follow developerWorks tweets.
- developerWorks podcasts: Listen to interesting interviews and discussions for software developers.
- developerWorks on-demand demos: Watch demos ranging from product installation and setup for beginners to advanced functionality for experienced developers.
Get products and technologies
- Saxon-CE Download the alpha release from the Saxonica website, along with sample applications and documentation.
- XML Prague
2011 (PDF file): Download the conference proceedings.
- IBM product evaluation versions: Download or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- The developerWorks community: Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.




