Wednesday, July 21, 2010

XSLT Tricks for CDA

There's a reason why HL7, IHE and HITSP profiles/implementation guides on CDA recommend or even require the Act.text and code.orginalText to be present in entries, and to point to the narrative text rather than duplicate it.  The key reason for having these present at all is to allow information systems to have access to the text values used in the exchange.  This supports exchange of the free text strings when two systems do not use the same coding systems (e.g., as for exchange of medication information under meaningful use).  The main reason for pointing to the content instead of duplicating it is to eliminate a potential source of error in implementation.  But another reason for pointing instead of duplicating is that it creates a link between the human readable text and the machine readable entry.  This link can be used in XSLT transformations to support features like mouseovers.

For example, suppose you had the following narrative content:

‹text›...‹content ID='problem-1'›Headache‹/content›...‹/text›

You can guess that because there is an ID attribute on the text element, something may be pointing to it.  Indeed, in this case, there is:

‹entry›
  ‹observation classCode='OBS' moodCode='EVN'›
      ...
    ‹code ...›
      ‹originalText›{reference value='#problem-1'›{/orginalText›
    ‹/code›
      ...
  ‹/observation›
‹/entry›

Now, if you wanted to generate a mouseover from this entry, it should be pretty simple.  Every element that contains an ID attribute should generate an HTML element with a title attribute that contains the text you want to show up on the mouseover.  This first template shows how you might handle the content element (note that you should do something similar for paragraph, list item and table elements, but I'll leave that as an excercise for the reader).

‹xsl:template match="cda:content"›
  ‹span›
    ‹xsl:apply-templates select="@*|*|text()"/›
  ‹/span›
‹/xsl:template›
This just wraps the content an HTML SPAN tag, and calls other templates to handle its content, including attributes, elements and text.

The next template handles the ID attribute.  When a content element contains an ID attribute, this template will be used:
‹xsl:template match="@ID"›
  ‹xsl:attribute name="ID"›
    ‹xsl:value-of select="."/›
  ‹/xsl:attribute›
  ‹xsl:variable name="theID" select="concat("#",.)"/›
  ‹xsl:apply-templates select="//cda:reference[@value=$theID]"/›
‹/xsl:template›
It copies the ID attribute to the HTML elementy generated (the SPAN tag used in the previous template), and then applies any template matching any reference element pointing to this ID.

You can see that template below.  The reference element can appear inside a code, routeCode or value element or in a text element inside the various acts (and a few others, but these are the key ones).  Having found the reference, this template finds the code element associated with it and applies a template on the code element that will generate the titel attribute.

‹xsl:template match="cda:reference"›
  ‹xsl:choose›
    ‹xsl:when test="../../self::cda:code|../../self::cda:routeCode|../../self::cda:value"›
      ‹xsl:apply-templates mode="code" select="../.."/›
‹/xsl:when›
    ‹xsl:when test="../self::cda:text"›
      ‹xsl:apply-templates mode="code" select="../../cda:code"/›
    ‹/xsl:when›
  ‹/xsl:choose›
  ‹xsl:text› ‹/xsl:text›
‹/xsl:template›
This next template finally generates the title attribute.
‹xsl:template match="cda:code|cda:value|cda:routeCode" mode="code"›
  ‹xsl:attribute name="title"›
    ‹xsl:value-of select="../../@codeSystemName"/›
    ‹xsl:if test="not(../../@codeSystemName)"›
      ‹xsl:value-of select="../../@codeSystem"/›
    ‹/xsl:if›
    ‹xsl:text›: ‹/xsl:text›
    ‹xsl:value-of select="../../@displayName"/›
    ‹xsl:text› ‹/xsl:text›
    ‹xsl:value-of select="../../@code"/›
  ‹/xsl:attribute›
‹/xsl:template›
This may appear to be a lot of work to generate a title attribute.  I could have written this quite a bit more simply, but I wanted to be able to use a similar XSLT to generate event method calls (onmouseover or onclick) that would do other sorts of cool things in the user interface for this stylesheet.

For meaningful users in the US, this is just one way that you can take advantage of the coded data present in the HITSP C32 specification.

Excercise:  Generate a CDA stylesheet that will display not just a mouse-over, but a popup window containing other data appearing in the entry.

2 comments:

  1. Keith,

    Thanks for the tips. I had a little trouble grasping the concepts at first, though. When you said "mouseovers" I THINK you meant that in the display of the narrative section, that there would be mouseovers that gave you additional details from the structured entries (e.g., mouse over the problem name and see the problem code that was not otherwise displayed in the narrative)? I guess I got a little lost because you first talked about tagging the original text problem-1, and there's no need to have a mouseover for that because it's already displayed. Before you went straight into the XML examples, I would have been helped by in initial statement of what the user would see and why this is helpful. Perhaps you could augment the last statement of your first paragraph to say "This link can be used in XSLT transformations to support features like mouseovers THAT DISPLAY ADDITIONAL DATA FROM THE STRUCTURED ENTRY THAT IS NOT PRESENT IN THE NARRATIVE BLOCK."

    Did I get that right?

    Thanks as always for your sharing of wisdom.

    David

    ReplyDelete