Wednesday, October 24, 2012

Styling CDA Based on Entry Content

I've long advocated that CDA Entries be linked back to the narrative text that they are associated with.  There are some very good reasons for doing this, and I discovered a new one yesterday.  What that allows you to do is set display formatting based on what the narrative content means.

Suppose you had the following content in your CDA document:

<table border="1">

  <thead>
    <tr><th>Severity</th><th>Problem</th><th>Date</th><th>Comments</th></tr>
  </thead>
  <tbody><tr>
    <td><content ID="severity-1">Severe</content></td>
    <td><content ID="problem-1">Ankle Sprain</content></td>
    <td>3/28/2005</td>
    <td><content ID="comment-1">Slipped on ice and fell</content></td>
  </tr></tbody>
</table>

Note the <content> elements and the ID attributes.

Assume you had an entry with the following content (I've removed all but the templateId and element container for the reference in the following for brevity):

<entry>
  <observation classCode="COND" moodCode="EVN">
    <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5"/>
      ...<value code="44465007" codeSystem="2.16.840.1.113883.6.96"
      codeSystemName="SNOMED CT" xsi:type="CV">
      <originalText><reference value="#problem-1"/></originalText>
    </value>...
    <entryRelationship inversionInd="true" typeCode="SUBJ">
      <observation classCode="OBS" moodCode="EVN">
        <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.1"/>

        ...<value code="H" codeSystem="2.16.840.1.113883.5.1063"

          codeSystemName="ObservationValue" displayName="High" xsi:type="CD">
          <originalText><reference value="#severity-1"/></originalText>
        </value>...

      </observation>
    </entryRelationship>
    <entryRelationship inversionInd="true" typeCode="SUBJ">
      <observation classCode="OBS" moodCode="EVN">
        <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.2"/>

        ...<text><reference value="#comment-1"/></text>...

      </observation>
    </entryRelationship>
  </observation>
</entry>

Note how each entry template includes a reference pointing back to the ID.  Let's classify each of these references:

#problem-1: References the name of the problem.  Suppose in this case, we'd like these to be in bold and small-caps.
#severity-1:  References the severity of theproblem.  We don't want to do anything special with these.
#comment-1: References the comment on the problem.  Suppose here we want this to be italicized, and furthermore, would like a mouse-over to display the author name.

This is a modest extension of the Stupid Mouse-Over trick that I teach when I talk about how to render CDA documents.  You'll need a template for each special style you want to apply, and you'll also need to apply a template to the ID attribute that you invoke for each CDA narrative element you process.

Here's the template for the ID attribute.

<xsl:template match="@ID">

  <xsl:attribute name="ID">
    <xsl:value-of select="."/>
  </xsl:attribute>
  <xsl:variable name="theID" select="concat('#',.)"/>
  <xsl:variable name="theRef" select="//cda:reference[@value=$theID]/../.."/>
  <xsl:apply-templates select="$theRef" mode="style">
    <xsl:with-param name="ID" select="."/>
  </xsl:apply-templates>
</xsl:template>

This template copies the ID to element you just created (e.g., <p>, <li>, <td> et cetera, using this mapping). It locates any references to that ID in entries anywhere within the CDA document, and calls a template to set the class attribute on the output element.  This template is invoked either on the value or code element (e.g., where originalText would appear), or on the entry element itself (when the reference appears in act/text).

The next two examples show how to create templates that would set the style to use for the problem name and severity.

<xsl:template match="cda:value[
  parent::cda:observation/cda:templateId/
    @root='1.3.6.1.4.1.19376.1.5.3.1.4.5']" mode="style">
  <xsl:attribute name="class">problem-name</xsl:attribute>
</xsl:template>

<xsl:template match="cda:value[
  parent::cda:observation/cda:templateId/
    @root='1.3.6.1.4.1.19376.1.5.3.1.4.1']" mode="style">
  <xsl:attribute name="class">severity</xsl:attribute>
</xsl:template>

You may recall that I said we don't want to do anything special for severity.  That's still true, but read on:

Here's the template for the comment.
<xsl:template match="cda:observation[
    cda:templateId/@root='1.3.6.1.4.1.19376.1.5.3.1.4.2']" mode="style">
  <xsl:param name="ID"/>
  <xsl:attribute name="class">comment</xsl:attribute>
  <xsl:attribute name="title"><xsl:apply-templates 
    select="ancestor-or-self::*[cda:author][1]/
     cda:author[descendant::cda:assignedPerson][1]" mode="title"/>
  </xsl:attribute>
</xsl:template>

I said we wanted a mouse-over to display the name of the author for the comment.  To do that, we'll assign a title attribute to the wrapping tag, and fill it in with the author name.  To do that, we have to find the author.  The select attribute of the apply-templates requires a little bit of explanation.  It locates any element ancestor where we have the reference that has an author.  These will be ordered in reverse document order.  The first of these will be the closest ancestor that assigns one or more authors to the entry.  From there, we select the authors who are people rather than devices (this is what descendant::cda:assignedPerson] does), and choose the first one of those (the [1]) to display in the title.

The final template converts a person name into a string appropriate for display in a title. It just concatenates the name parts with a space delimiter after each one (a purist would strip off the last space, but for this demonstration it doesn't matter).

<xsl:template match="cda:author" mode="title">

  <xsl:for-each select="./cda:assignedAuthor/cda:assignedPerson/cda:name/cda:*">
    <xsl:value-of select="."/>
    <xsl:text> </xsl:text>
  </xsl:for-each>
</xsl:template>

Finally, somewhere at the top of the XSLT stylesheet, you need to output a <style> element that contains the following:

<style>

  ...

  .problem-name { font-weight: bold; font-variant: small-caps; }
  .severity { }
  .comment { font-style: italic; }
</style>

While we assign a class to severity in the generated HTML, the style associated with that class does nothing.  This allows me to change my mind later about how severity would be represented in the output.

Using the sample file that I started with (one I used for CRS Release 1), the result looks something like this.  Note that while I started with something old, the same techniques can be applied to CCD, C-CDA or any other set of templates using the CDA standard.

Good Health Clinic Care Record Summary

Conditions

SeverityProblemDateComments
Severe Ankle Sprain 3/28/2005 Slipped on ice and
fell

ONC Challenge

ONC yesterday issued a design challenge for Blue Button.  It should be fairly straight-foward to apply this technique in a CDA Stylesheet that implements one of the chosen designs.  What this technique does support is applying specific styles to narrative content that already appears and is linked to entries.  What it won't do is generate narrative from the entries.  For that, you'd need a different kind of style sheet, and that would need to be used by producers of CDA documents, rather than consumers of them.  This technique can be used by either producers or consumers.

0 comments:

Post a Comment