Adapted and maintained by: Alexander Henket, Nictiz, The Netherlands, henket(a)nictiz.nl
Purpose: Provide general purpose display of CDA release 2 (Specification: ANSI/HL7 CDAR2)
and CDA release 3 (Specification: currently in ballot) documents, and be a starting
point for people interested in extending the display. This stylesheet displays all
section content, but does not try to render each and every header attribute. For header
attributes it tries to be smart in displaying essentials, which is still a lot.
License: Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
History: This stylesheet stands on the shoulders of giants. The stylesheet is the cumulative
work of several developers; the most significant prior milestones were the foundation
work from HL7
Germany and Finland (Tyylitiedosto) and HL7 US (Calvin Beebe), and the presentation
approach from Tony Schaller, medshare GmbH provided at IHIC 2009. The starting point
for this work was/is hosted at
http://www.lantanagroup.com/resources/tools/.
TODO
Remove any temporary cruft from the CDAr3 ballot that does not make it into the final
version
Fix for Mobile Safari (iOS 6): doesn't support opening the table of contents
Revisions
05/30/2013 AH
Made parameters out of font-family and font-sizes for the main font, h1-h6, and footers
Font-sizes are now all in points rather than pixels and points so more reliable in
rendering
Fixed getLocalizedString so it now does a lowercase comparison of the language
Added German translations for Table of Contents and Show/Hide revisions
05/29/2013 AH
Internet Explorer update: disabled the use of textEncoding, otherwise it would not render
Fixed font-size problem for Internet Explorer 8 - it doesn't inherit size in td tags
Fixed table of contents problem for Internet Explorer 8 - wouldn't open
Fixed #documentfooter style
Pulled bgcolor in the header and footer part into CSS so it may be overridden
05/28/2013 AH
Redesigned the setup. Now has three main divs.
#documentheader contains basic Patient and Author info
#documentbody contains section content
#documentfooter contains all relevant CDA header info
Updated for CDA release 3 as of Ballot May 2013. Includes datatypes awareness in alle
relevant places This update is largely about feature parity
Added <oXygen/> style documentation tags to facilitate HTML documentation
05/22/2013 AH
Added parameter for external css if so desired
06/28/2011 AH
Improved show-id by diplaying nullFlavor where applicable
05/31/2011 AH
Improved show-code to return translated codes, and finally the original code if originalText
and @displayName fail
Improved label on bottom participant to include translated assignedEntity/code if
available
Improved readability of participant/assignedEntity
05/30/2011 AH
Participant codes are now displayed by default instead of only when the name is omitted
Fixed translation of patientIdLong, by using the literal string instead treating it
as a node
Improved title on ids in fixed top header by adding a newline between multiple ids
Changed behavior of "Waarschuwingen" and "Behandelaanwijzigingen" to display "Er zijn
geen ..." if they are not applicable, instead of showing nothing
Changed "Behandelaanwijzingen into "Behandelrestricties"
05/03/2011 AH
Added language file and a template getLocalizedString to deal with it
Added parameter textLang to feed the desired language. Does not work with just a browser,
so textLang needs to be set in any environment
Replaced all current text in the stylesheet with calls to getLocalizedString
Improved layout of page so there's now a fixed header. Shrunk the TOC into a button
with hover to open so it doesn't always take up all screen space. The layout is enforced
using div with an id To avoid lots of scrolling in the header area this part needed
to be predictable and small. All header info except recordTarget is now to the bottom
of the document Also the document title was made less big
Added support for every styleCode in CDA release 2, not just bold/italics/underline,
but also all list styles and e.g. Botrule
Added support for footnotes/footnoteRefs
Added support for multiple section authors (used to be just one, and support was bugged)
Added support for (multiple) section informants
Added support for section subject
Added support for @ID, @IDREF, @language, and all other style properties from CDA
release 2
Added support for the display of nonXMLBody with text/plain content
Added support for Narrative block <linkHtml/>
Added support for revisions. Deletions will get a strikethrough, Insertions an underline
and overline Both get a title saying 'delete' or 'insert'. This feature is off by
default, but above the TOC there's a toggle to switch revisions marks on or off. A
little Javascript was used for that.
Added confidentiality to the title of the document if present and other than N (Normal).
If someone took the effort to send the confidentiality it should be 'in your face'
as recipient.
Added support for multiple section authors (used to be just one, and support was bugged)
Added support for (multiple) section informants
Added support for section subject
Added a switch to diable Javascript in case the environment requires that
Improved support for data type II when there's only a root and no extension
Improved support for the author organization which not displayed
Improved support for telecom and addr use codes. Now supports multiples
Improved support for names. Now gets out every node, supporting mixed mode too.
Improved readability for the support for lists by combining the two templates
Improved support for observationMedia by removing the limitation of just gif and jpeg.
If the browser does not support a given type, then at least a question mark is displayed.
Before there was nothing
Improved support for observationMedia by adding the id (if available) to the alt and
title of the image
Added support for inline base64 images. HTML actually can deal with that too
Improved handling of addresses so it now walks through all nodes, support mixed content.
Also, the elements are now handled in the order of the instance and not just US order
Improved support for dates by including a language switch. Now just handles en-US
and nl-NL, but could handle more Likely more sophisticated support is in order, but
this works for our purposes while leaving US conventions intact
Improved handling of names, addresses and telecom. The templates gave incorrect results
for multiples of these, mixing the contents of the latter with the first. Added name
use code to the display of names if available.
Fixed the author string in the main document info. It used to '-', but is now "Author"
in any supported language
<xsl:template match="hl7:component/hl7:nonXMLBody"><xsl:choose><!-- if there is a reference, use that in an iframe --><xsl:when test="hl7:text/hl7:reference"><iframe name="nonXMLBody" id="nonXMLBody" width="100%" weight="600" src="{hl7:text/hl7:reference/@value}"/></xsl:when><xsl:when test="not(hl7:text/@mediaType) or hl7:text/@mediaType='text/plain'"><pre><xsl:value-of select="hl7:text/text()"/></pre></xsl:when><xsl:when test="starts-with(hl7:text/@mediaType,'image/')"><img><xsl:attribute name="alt"/><xsl:attribute name="title"/><xsl:attribute name="src"><xsl:value-of select="concat('data:',hl7:text/@mediaType,';base64,',hl7:text)"/></xsl:attribute></img></xsl:when><xsl:when test="hl7:text/@representation='B64'"><xsl:call-template name="getLocalizedString"><xsl:with-param name="key" select="'If the contents are not displayed here, it may be offered as a download.'"/></xsl:call-template><iframe name="nonXMLBody" id="nonXMLBody" width="100%" height="600"><xsl:attribute name="src"><xsl:value-of select="concat('data:',hl7:text/@mediaType,';base64,',hl7:text)"/></xsl:attribute></iframe></xsl:when><xsl:otherwise><center><xsl:call-template name="getLocalizedString"><xsl:with-param name="key" select="'Cannot display the text'"/></xsl:call-template></center></xsl:otherwise></xsl:choose></xsl:template>
Produces a section title with at least an anchor based on relative position in the
document (for the Table of Contents), and a second anchor if the section has the @ID
tag
<xsl:template name="section-title"><a><xsl:attribute name="name"><xsl:apply-templates select="." mode="getAnchorName"/></xsl:attribute></a><xsl:if test="@ID"><a name="{@ID}"/></xsl:if><h3><xsl:if test="hl7:code"><xsl:attribute name="title"><xsl:call-template name="show-code-set"><xsl:with-param name="in" select="hl7:code"/><xsl:with-param name="sep" select="', '"/></xsl:call-template></xsl:attribute></xsl:if><xsl:choose><xsl:when test="count(/hl7:ClinicalDocument/hl7:component/hl7:structuredBody/hl7:component[hl7:section]) > 1"><!-- Add link to go back to top if the document has more than one section, otherwise superfluous --><a href="#toc"><xsl:apply-templates select="." mode="getTitleName"/></a></xsl:when><xsl:otherwise><xsl:apply-templates select="." mode="getTitleName"/></xsl:otherwise></xsl:choose></h3></xsl:template>
Handle footnoteRef. Produces a superscript [n] where n is the occurence number of
this ref in the
whole document. Also adds a title with the first 50 characters of th footnote on the
number so you
don't have to navigate to the footnote and just continue to read.
Namespace
No namespace
Match
hl7:footnoteRef
Mode
#default
Import precedence
0
Source
<xsl:template match="hl7:footnoteRef"><xsl:variable name="idref" select="@IDREF"/><xsl:variable name="footNoteNum"><xsl:for-each select="//hl7:footnote"><xsl:if test="@ID=$idref"><xsl:value-of select="position()"/></xsl:if></xsl:for-each></xsl:variable><xsl:variable name="footNoteText"><xsl:copy-of select="//hl7:footnote[@ID=$idref]//text()"/></xsl:variable><sup><xsl:text>[</xsl:text><a href="#{$idref}"><!-- Render footnoteref with the first 50 characters of the text --><xsl:attribute name="title"><xsl:value-of select="substring($footNoteText,1,50)"/><xsl:if test="string-length($footNoteText)>50"><xsl:text>...</xsl:text></xsl:if></xsl:attribute><xsl:value-of select="$footNoteNum"/></a><xsl:text>]</xsl:text></sup></xsl:template>
Handle RenderMultiMedia. This currently only handles GIF's and JPEG's. It could, however,
be extended
by including other image MIME types in the predicate and/or by generating <object>
or <applet>
tag with the correct params depending on the media type @ID =$imageRef referencedObject
Namespace
No namespace
Match
hl7:renderMultiMedia
Mode
#default
Import precedence
0
Source
<xsl:template match="hl7:renderMultiMedia"><xsl:variable name="imageRef" select="@referencedObject"/><xsl:choose><xsl:when test="//hl7:regionOfInterest[@ID=$imageRef]"><!-- Here is where the Region of Interest image referencing goes --><xsl:choose><xsl:when test="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia/hl7:value[@representation='B64']"><xsl:variable name="mediaType" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia/hl7:value[@representation]/@mediaType"/><xsl:variable name="string" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia/hl7:value[@representation]"/><xsl:variable name="mediaIdRoot" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia[hl7:value/@representation]/hl7:id/@root"/><xsl:variable name="mediaIdExt" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia[hl7:value/@representation]/hl7:id/@extension"/><br clear="all"/><xsl:element name="img"><xsl:attribute name="alt"><xsl:if test="string-length($mediaIdRoot) or string-length($mediaIdExt)"><xsl:value-of select="concat('id = ',$mediaIdRoot,' ',$mediaIdExt)"/></xsl:if></xsl:attribute><xsl:attribute name="title"><xsl:if test="string-length($mediaIdRoot) or string-length($mediaIdExt)"><xsl:value-of select="concat('id = ',$mediaIdRoot,' ',$mediaIdExt)"/></xsl:if></xsl:attribute><xsl:attribute name="src"><xsl:value-of select="concat('data:',$mediaType,';base64,',$string)"/></xsl:attribute></xsl:element></xsl:when><xsl:when test="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia/hl7:value/hl7:reference/@value"><xsl:variable name="mediaIdRoot" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia[hl7:value/hl7:reference]/hl7:id/@root"/><xsl:variable name="mediaIdExt" select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia[hl7:value/hl7:reference]/hl7:id/@extension"/><br clear="all"/><xsl:element name="img"><xsl:attribute name="alt"><xsl:if test="string-length($mediaIdRoot) or string-length($mediaIdExt)"><xsl:value-of select="concat('id = ',$mediaIdRoot,' ',$mediaIdExt)"/></xsl:if></xsl:attribute><xsl:attribute name="title"><xsl:if test="string-length($mediaIdRoot) or string-length($mediaIdExt)"><xsl:value-of select="concat('id = ',$mediaIdRoot,' ',$mediaIdExt)"/></xsl:if></xsl:attribute><xsl:attribute name="src"><xsl:value-of select="//hl7:regionOfInterest[@ID=$imageRef]//hl7:observationMedia/hl7:value/hl7:reference/@value"/></xsl:attribute></xsl:element></xsl:when></xsl:choose></xsl:when><xsl:otherwise><!-- Here is where the direct MultiMedia image referencing goes --><xsl:if test="//hl7:observationMedia[@ID=$imageRef]/hl7:value[@mediaType='image/gif' or @mediaType='image/jpeg']"><br clear="all"/><xsl:element name="img"><xsl:attribute name="alt"><xsl:if test="//hl7:observationMedia[@ID=$imageRef]/hl7:id"><xsl:value-of select="concat('id = ',//hl7:observationMedia[@ID=$imageRef]/hl7:id/@root,' ',//hl7:observationMedia[@ID=$imageRef]/hl7:id/@extension)"/></xsl:if></xsl:attribute><xsl:attribute name="src"><xsl:value-of select="//hl7:observationMedia[@ID=$imageRef]/hl7:value/hl7:reference/@value"/></xsl:attribute></xsl:element></xsl:if></xsl:otherwise></xsl:choose></xsl:template>
Show elements with datatype II separated with the value in 'sep'. Calls show-id
Parameters
in
Set of 0 to * elements
sep
Separator between output of different elements. Default ', ' and special is 'br' which
generates an HTML br tag
Description
======================================================================
Datatype based functions
======================================================================
Retrieves a language dependant string from our language file such as a label based on a key. Returns string based on textLang, textLangDefault, the first two characters of the textLangDefault, e.g. 'en' in 'en-US' and finally
if all else fails just the key text.
Parameters
pre
Some text or space to prefix our string with
key
The key to find our text with
post
Some text like a colon or space to postfix our text with
Default language for retrieval of language dependant strings such as labels, e.g.
'en-US'. This is the fallback language in case the string is not available in the
actual language. See also textLang.
Actual language for retrieval of language dependant strings such as labels, e.g. 'en-US'.
Unless supplied, this is taken from the ClinicalDocument/language/@code attribute,
or in case that is not present from textlangDefault.
Currently unused. Unsupported by Internet Explorer. Text encoding to render the output
in. Defaults to UTF-8 which is fine for most environments. Could change into more
localized encodings such as cp-1252 (Windows Latin 1), iso-8859-1 (Latin 1), or shift-jis
(Japanese Kanji table))
Boolean value for whether the result document may contain JavaScript. Some environments
forbid the use of JavaScript. Without JavaScript, certain more dynamic features may
not work.
Absolute or relative URI to an external Cascading Stylesheet (CSS) file that contains
style attributes for custom markup, e.g. in the @styleCode attribute in Section.text