Health Level 7 (HL7) Clinical Document Architecture (CDA) 基于 HL7 version 3 参考信息模型 (RIM),该模型用于开发 HL7 v3 消息传递。HL7 消息传递表示个人医疗保健交互(比如查询、响应和通知),而 HL7 CDA 文档则是单个持久化文档,用于表示患者就诊、持续监护 (continuity-of-care) 等类似文档。为了便于人们阅读 CDA 中的信息,每个 CDA 文档除了包括机器可读的内容外,还要有一个文本描述,如 清单 1 所示。严格说来,HL7 v3 消息旨在通过电缆传输(例如,作为 “客户端对服务器” 交互或 “服务器对服务器” 数据分发的一部分);由于它们也用来供人类阅读,所以还可以通过其他方式(比如电子邮件)来传输 HL7 CDA 文档。
清单 1. CDA 中的一条观察条目:Penicillin 过敏症状
<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>
|
Saxon 分析器提供在服务器端上运行 XSLT 2.0 转换的支持已经有许多年了。在最近的 2011 XML Prague 会议上,Saxon 分析器的原创者 Michael Kay 博士介绍了 Saxon Client Edition (Saxon-CE) 的 alpha 版本,该版本支持在 Web 客户端应用程序(在浏览器中)中直接运行 XSLT 2.0 转换。使用 JavaScript 在任意现代浏览器上运行 Saxon-CE,这一直都是关于客户端 XSL 的研究问题:历来各种浏览器都没有统一地实现 XSL 支持。由于 Saxon-CE 采用了 JavaScript 作为运行时引擎,因此解决了此问题。
另外,XSLT 2.0 提供了几个原先 XSLT 1.0 规范所不支持的特性,比如支持多个文档和更强的数据类型设置。Saxon-CE 问世后,这些特性现在在客户端中均受到支持,如本文所示,其中有些特征非常适合用于客户端应用程序视图,特别是多个文档的客户端支持。
在开发本文描述的 CDA Viewer 应用程序,我使用了 Unite Web 服务器,它是 Opera 最新版本所附带的服务器。您也可以使用您喜欢的任何服务器。由于本文讨论的是如何开发一个客户端应用程序视图,所以不再介绍如何持久化或分发 CDA 文档。在应用程序的测试方面,我直接通过 Web 服务器将一个样例 CDA 发布为一个 URL(或者,您也可以将您的 CDA 文档持久化到 IBM® DB2® pureXML 之类的 XML 数据库中)。同样的,我也将 XSL 转换发布为 URL。
Saxon-CE alpha 版本目前可以从 Saxonica 网站上下载(参见 参考资料 中的链接)。目前,该 alpha 版本还不能用于生产应用程序;但是,基于原先 Saxon 分析器的成功,我确信,Client Edition 将很快成为行业标准,尤其是如果它能赢得来自早期使用者的积极反馈的话。
这个 alpha 版本附带了丰富的发布说明。您可以将解压的发布文件夹中的 JavaScript 文件以及其他任何 .js 脚本复制到您的应用程序服务器。您还应该花点时间下载样例应用程序。该 JavaScript 包含了一个 .nocache.js 文件和几个缩小的 .js 文件,每个文件针对于每个主要浏览器。这些文件包含实际的分析器代码;.nocache.js 文件先检测使用的是哪个浏览器,然后再调用相应的 .js 脚本。样例应用程序包含一个 XSL 转换文件、一些 XML 数据以及一个 HTML 文件,该文件会调用 Saxon-CE JavaScript 脚本来运行转换。我构建的 CDA Viewer 应用程序遵循相同的模式,但是为了可读性,我将转换层拆分为三个文件(参见 下载 部分)。在 Web 服务器上,我为每个样例应用程序各安排一个文件夹,还为 CDA 应用程序安排了一个文件夹。
XSLT 2.0 规范引入了很多特性,比如函数定义、多结果文档、序列和临时树、更强的类型设置以及文本分析。本文主要关注多结果文档支持。在服务端,使用多结果文档意味着在服务器上创建多个文档,这样就能创建一个 XHTML 主页来引用服务器上生成的其他几个结果页。在服务端转换上,使用多结果文档仅仅意味着:多个文档。清单 2 展示了这种解决方法。使用 Saxon-CE 在客户端上生成多个文档时,生成的内容实际上指向您的客户端应用程序的各个屏幕区域(通常是 HTML 页中的 div 元素)。
清单 2. (服务器上的)多结果文档
<xsl:for-each select="section">
<xsl:result-document href="{@id}.html">
<xsl:apply-templates select="." mode="html" />
</xsl:result-document>
</xsl:for-each>
|
我将 XSL 转换分为三个文件(参见 下载 部分):
- cda.xsl:包含基本转换,用于显示人类可读文档。
- cda-machine-readable.xsl:包含一个可定制层,目前可以一种更整洁的方式显示机器可读的文档细节。
- cda-dom-interaction.xsl:包含一个模板,用于处理与 HTML 页的 DOM 之间的交互,比如单击事件。
另外,本身还有一个 CSS 文件和 HTML 页。
CSS 比较简单。HTML 页也比较简单,只包含几个用于 CDA Viewer 中各屏幕区域的 div 元素,每个元素都可以通过一个 ID 在 CSS 中定位。我的计划是加载并转换整个 CDA,然后允许通过 DOM 进行交互式访问,这样我就能拥有一个名为 div-cache 的 div 元素,我将该元素隐藏在 CDA Viewer 底部。这个缓存包含 CDA 中所记录的每个条目的副本。您可以向下滚动查看文本,也可以将这个元素标记为 style="visibility:hidden;inline:none",使其隐藏起来。
清单 3 中的代码用于触发转换过程。如您所见,<script> 标记首先会调用 Saxon-CE JavaScript,然后再调用 XSL 转换样式表,以 CDA 文档为目标。
清单 3. 从 HTML 页调用 Saxon-CE
<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>
|
在 清单 3 中,主转换首先从 CDA 包装器中提取一些信息,为 CDA Viewer 创建一个简明标题。而且,您能够看到 xsl:result-document 的运行效果。在 清单 4 中,注意一下 <div> 标记是如何通过其 #creation ID 标识的。method="ixsl:replace-content" 是 “in the interactive XSL, replace the content” 的简写。稍后您将看到一个附加内容的示例。注意,当您直接处理 CDA 时,只要一引用 CDA 中的元素,都需要使用 hl7: 命名空间。稍后您将看到,在处理引用 DOM 的模板时,并不需要这样做。这个过程可能比较麻烦,这也是我将模板拆分为几个 XSL 样式表的原因之一。
清单 4. 使用 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>
|
在同一个 XSL 文件中的下一个代码段(参见 清单 5)中,您将看到如何从 CDA 文档中的各个部分生成 CDA Viewer 目录。请您查看一些关于目录格式化详细信息的样例文件。我们采用了一种类似的方法来缓存来自 CDA 的临床输入数据。在这两个案例中,您可以了解到,在每次应用模板时结果是如何被附加到目标 <div> 元素的现有内容的。
清单 5. 使用 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>
|
图 1 展示了基本 CDA Viewer 和目录。
图 1. CDA Viewer 目录
所生成的 ID 用于将目录中的链接与缓存中的 CDA 条目相连接起来。清单 6 提供了用于在目录中创建条目的模板的一个节选。
清单 6. 链接到缓存的 CDA 条目
<a class="notes-section">
<xsl:attribute name="id"><xsl:value-of select="generate-id(.)"/></xsl:attribute>
<xsl:value-of select="hl7:title"/>
</a>
|
在 清单 7 中,注意下如何使用模板上的 mode="ixsl:onclick" 属性来告知 Saxon-CE 应用这个模板来处理单击事件。这与其他的 JavaScript 单击事件相似:仅通过 Saxon-CE 和 XSL 样式表处理。注意,只要分析器处理这类单击事件,上下文就会从原始 XML 文档转移到 HTML 页的 DOM,这也是我将这些模板单独放置到一个名为 cda-dom-interaction.xsl 的转换样式表中的原因。模板本身显示 CDA 条目的文本,
该条目是从此前用原始单击事件相关联 ID(原始锚链接的 ID)所创建的缓存中提取的。这个文本替换 note-detail 结果文档 div element 的内容。然后模板会应用任何适用的下游模板来处理 CDA 条目中的机器可读内容。
清单 8. 处理来自目录的单击事件
<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>
|
为了隔离机器可读内容和人类可读内容,我创建并包含了一个第三个转换样式表 cda-machine-readable.xsl。隔离这些模板有这样一个好处:可以对第三个样式表进行扩展或完全替换,以便使用一个更复杂的样式表来处理 CDA 中的机器可读信息。例如,您可能想提供更美观的表或数据图形表示,或者保持某些条目类型。或者,您可能想深入一步,加载另一个 XML 文档(也许是从一个元数据存储库加载),扩展机器可读数据中的一些代码,或者使用常用代码系统对它们进行归类。保留模板来转换机器可读条目是一种良好编程实践,正如通常分隔关注问题那样。当我处理大规模转换或我期望执行的转换时,我发现这种实践非常关键。
我的最小机器可读转换样式表只包含单个模板,该模板标识若干已知条目类型(Observation、Substance Administration、Procedure 和 Act 事件)并使用项目列表和表样式化它们。我并不打算在这里做一些太花哨的事情,但查看一个简单模板如何通过样式和组织提供丰厚的回报是一个有用的练习。还要注意下,在 清单 8 中,起源锚链接是如何通过一个参数被传递给模板。这个步骤对于显示机器可读数据不是必要的。恰恰相反,链接要通过这个模板传递,并缓存在条目细节底部的一个隐藏的 div 元素中以便将来使用。这个链接信息稍后将用于构建我所说的别针区域 (pin area)。为简洁起见,我省去了所有内容,只保留了针对 xsl:choose 中的 Observation 的 xsl:when。
清单 8. 模板化机器可读的 CDA 的条目
<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>
|
注意,由于这个模板应用于缓存在 DOM 中的 CDA 数据副本,hl7: 不是 entry、code 和 observation 等元素所必需的。您也可以将这个命名空间添加到缓存的 CDA 条目,但这样做没有多少好处,因为不会进一步执行序列化。如果页面上的 HL7 CDA 元素和其他元素之间存在混淆,这样做具有实际意义。
图 2 展示了一个 CDA Viewer,其中包含了一个表示过敏和不良反应的观察事件。
图 2. 诸如过敏和不良反应的观察事件
别针区域是在开发转换过程中出现的一种设计模式,它是受到 Saxon-CE 实现 XSLT 2.0 结果文档的方法所启发的。如前所述,生成的内容可以附加到一个屏幕区域,也可以替换现有内容。通常,您需要替换现有内容;但是,当您重复应用一个模板时,就可能需要附加内容。如果您将几个模板应用到同一个目标屏幕区域,那么可以创建一个类似于书签的集合:您可以以交互式方式逐渐添加这个集合,而不必移除屏幕区域中的任何现有内容。
在 清单 9 中的样例代码中,查看模板以固定锚链接。没错,这是一个样例应用程序,但这里的理念可以向您提供启发。当您单击这个 Viewer 的目录中的链接时,这个链接事件的处理方法是显示 CDA 的那个部分的内容。但是,当您单击其他链接时,一个简单的锚模板将处理链接事件并将链接的内容复制到别针区域。结果是您可以使用 Viewer 来查看临床文档的内容并 “固定” 一些条目以便将来参考。
清单 9. 模板化别针区域
<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>
|
图 3 展示了别针区域的应用情况。
图 3. CDA Viewer 的别针区域
当然,如果您能使用固定的条目来做一些有用的事,那么这种设计模式会带来更多的好处;但是,关于这方面的讨论已超出了本文的范围。一个可能的使用案例可能要包含一个电子邮件浏览器插件,该插件可允许患者查看来自其医生的 CDA,固定一些条目,然后将它们包含到一个电子邮件响应中。由于它们处理信息的声明性方式,毫无疑问,Saxon-CE 和 XSLT 2.0 将是开发这些应用程序的有用工具。
CDA 文档是持久性文档,因此通常相当大。尽管旨在供人类阅读,但 CDA 文档中仍然包含了大量的机器可读信息,可以通过将这些信息转换为一个扩展的客户端视图使其易于管理。我敢肯定,随着未来版本的发布,Saxon-CE 将成为实现上述目标的关键工具,原因有两个:它能在任何现代浏览器上运行;它能提供一些客户端 XSLT 2.0 特性,比如多结果文档支持。我完全相信这种技术将成为富医疗保健应用程序开发人员必不可少的技术。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 样例 CDA 应用程序 | cda_sample.zip | 16KB | HTTP |
学习
- XML for Data: XSLT 2.0: An early look(Kevin Williams,developerWorks,2002 年 7 月):回顾众多 XSLT 2.0 特性,以及展示这种 XML 样式语言用途的代码样例。
- Compiling Saxon using GWT(Michael Kay 博士,Saxon diaries,2010 年 11 月):在这篇博文中,了解如何使用 Google Web Toolkit 将 Saxon 分析器从 Java™ 移植到 JavaScript。
- HL7 Clinical Document Architecture:阅读美国医疗信息协会会刊,进一步了解 HL7 CDA。
- HL7 version 3: Message or CDA Document?:阅读 Ringholm 上的这篇信息丰富的文章,深入了解 HL7 v3 消息传递和 CDA 之间的区别。
- 本文作者的更多文章(Piers Michael Hollott,developerWorks,2010 年 11 月至今):阅读关于 DITA 和其他技术的文章。
- XML 新手入门:获取了解 XML 所需的资源。
- developerWorks 中国网站 XML 技术专区:在 XML 专区查找提高您的技能所需的资源,包括 DTD、架构和 XSLT。参见 XML 技术文档库,阅读广泛的技术文章、技巧、教程、标准和 IBM 红皮书。
- IBM XML 认证:了解如何才能成为一名 IBM 认证的 XML 和相关技术的开发人员。
- developerWorks 技术活动 和 网络广播:随时关注这些活动中的技术。
- Twitter 上的 developerWorks:立即加入,了解 developerWorks 上的活动信息。
- developerWorks 播客:收听面向软件开发人员的有趣访谈和讨论。
- developerWorks 演示中心:观看面向初学者的产品安装和设置演示,以及为经验丰富的开发人员提供的高级功能。
获得产品和技术
- Saxon-CE:从 Saxonica 网站下载这个 alpha 版本,以及 样例应用程序 和文档。
- XML Prague
2011(PDF 文件):下载会议纪要。
-
IBM 产品评估试用版软件:下载或 IBM SOA 人员沙箱,并开始使用来自 DB2®、Lotus®、Rational®
、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
讨论
- XML 专区讨论论坛:参与任何一个 XML 相关讨论。
- 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和 wikis,并与其他 developerWorks 用户交流。