Showing posts with label SVS. Show all posts
Showing posts with label SVS. Show all posts

Tuesday, April 17, 2012

Clinical Quality Workgroup -- Essential Elements Tiger Team

The HIT Standards Clinical Quality Workgroup is rapidly closing in on its initial recommendations for making value sets accessible.  We reviewed 4 recommendations on our call yesterday:

Within our scope was making recommendations in support of a short-term value set infrastructure enabling Stage 2 quality measure deployment.  Out of scope was the longer term infrastructure.  

The recommendations we discussed are listed below briefly.
  1. Establish NLM as a single authority to validate value sets used in Stage 2 quality measures.
  2. Ask ONC to expedite recommendations made by the workgroup in January this year (especially see slide 20) and by the Vocabulary Task force in April of 2010 (powerpoint).
  3. Specify the standards to use for exchange of value sets.  Two choices were presented:
    1. IHE Sharing Value Sets
    2. HL7/OMG Clinical Terminology Services 2.0
  4. Enable web access for human and machine readable consumption. 
On the first two topics, the workgroup appeared to be in good agreement.

CTS2 and IHE SVS
I was caught a bit off-guard with respect to recommendation #3 becausethe workgroup had already developed a consensus on recommending the IHE SVS profile on the call last week.  It appears that there were some observers that were concerned about the use of that profile, especially since such a recommendation appeared to exclude the use of CTS in the architecture (even though it doesn't as I explain below).

The situation is a bit confusing for many:  The IHE Sharing Value Sets profile is a simple implementation of two of the APIs described in the CTS 1 and CTS 2 specifications.  It is designed for a very simple use case of searching for and downloading value sets.  It is NOT designed to support broad management capabilities needed to maintain, validate or curate value sets.

The CTS standard originated as version 1.0 in HL7.  CTS 2.0 became a joint HL7/OMG work effort, with HL7 defining essentially a functional specification, and OMG defining an implementation of that functionality.  This pattern has been used in many HL7 / OMG collaborations. 

I think the reason that the workgroup struggled with the question is because the scope was sharply defined with respect to implementation urgency.  If you are going to develop a vocabulary (value set) maintenance infrastructure, you should be applying an architecture that accounts for standards like CTS, whether your view be short term or long term.  However, regardless of what the architecture is, for the purpose of deployment of value sets to Health IT systems.  They don't need an extensive API in order to access identified value sets.  What they need is very simple.

As always, when posed with an either/or question, the answer is usually to restate the question.  Both CTS2 and IHE SVS are pertinent and appropriate for the infrastructure.  The Infrastructure should be oriented around CTS (long term), but APIs to access and download value sets should include IHE SVS (short term). 

Enabling Web Access
On the final recommendation, the workgroup also struggled a bit.  We kept falling into the trap of solution vs. requirement. The key requirement for web access is that there be a single source of truth for value sets.  Whether that requirement is met by a single host (web site) through which access is granted, or multiple hosts accessing a singular database or service supplying the content, or a model of deployment supported via replication or federation is not material.  We were well in agreement on there being a single source of truth for value set deployment but kept getting confused in drafting our recommendation by specifying solutions that meet that goal.

Coordination
There was insufficient time for me to bring up one issue that I am concerned about.  At present, NLM, AHRQ, CDC and ONC are all expending efforts on managing vocabulary and/or value sets for a variety of different purposes.  I'd like to see better use of HHS resources applied to the management of vocabulary and value sets, without so much duplication of effort.  

Friday, March 9, 2012

Implementing IHE SVS Over the Trifolia Consolidated CDA Database


This 32 line program is for a JSP Page to create an IHE SVS Value Set implementation over the Trifolia Workbench database that I've been playing around with.  It's got absolutely NO error handling, it just gets the material out of the valueset, valuesetmember and dictionarycodesystem tables if the parameter matches.

It was inspired by a brief e-mail exchange with Jacob Reider on the value of ONC creating a proof of concept repository.  Trifolia had most of what I needed in it for the database structure.  It either needs a version column added to the valueset and valueset member table, or some other minor restructuring so a valuesetmember can appear in multiple valueset versions (e.g., via an association table) to support version management, but is good enough for now for Consolidated CDA Implementors.

Since I need a working SVS repository for my QueryHealth work, I decided to throw this together and see how fast I could do it.  It took me about an hour to reconfigure my Eclipse install (I just got a new system and migrated all the software over using laplink, some of the configuration parameters needed debugging because file system locations had change).  The rest of the time was spend refreshing myself on JSTL.  It was done in less than two hours.

Here's the code:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<svs:RetrieveValueSetResponse xmlns:svs="urn:ihe:iti:svs:2008" xmlns:html="http://www.w3.org/1999/xhtml"><%@
 taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %><%@ 
 taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ 
 taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" 
%><sql:setDataSource var="snapshot" driver="com.mysql.jdbc.Driver"
 url="jdbc:mysql://localhost:3306/templatedb"
 user="user"  password="password"
/><sql:query dataSource="${snapshot}" var="valueset"
>SELECT valueSetName, description, ID from valueset WHERE OID = ?;
   <sql:param>${param.id}</sql:param>
</sql:query>     
<svs:ValueSet version="" displayName="${valueset.rowsByIndex[0][0]}" id="${param.id}">
<svs:ConceptList xml:lang="en-US">
<sql:query dataSource="${snapshot}" var="members"
>SELECT m.code code, m.displayName displayname, m.codeSystemOID codeSystemOID, cs.codeSystemName codeSystemName
FROM valuesetmember m 
LEFT JOIN dictionarycodesystem cs 
ON m.codeSystemOID = cs.OID 
WHERE m.valueSetOId = ?;
   <sql:param>${param.id}</sql:param>
</sql:query
>
<c:forEach var="row" items="${members.rows}">
<svs:Concept code="${row.code}" displayName="${row.displayName}" codeSystem="${row.codeSystemOID}" codeSystemName="${row.codeSystemName}" />
</c:forEach>
</svs:ConceptList>
</svs:ValueSet>
</svs:RetrieveValueSetResponse>


How to use it:
  1. Install MySQL Community Edition and JDBC Drivers
  2. Install The Trifolia Workbench (zip)
  3. Install the JSTL Libraries and MySQL JDBC Drivers into your Web Application
  4. Copy the above into RetrieveValueSet.jsp
  5. Change the user and password parameters above to match what is needed for your MySQL installation.
  6. Add the following lines to web.xml in your WEB-INF folder:
<servlet>
<description>A Servlet conforming to the IHE SVS Profile</description>
<display-name>IHE SVS Servlet</display-name>
<servlet-name>RetrieveValueSet</servlet-name>
<jsp-file>/RetrieveValueSet.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>RetrieveValueSet</servlet-name>
<url-pattern>/RetrieveValueSet</url-pattern>
</servlet-mapping>

Try it out.


Thursday, January 26, 2012

The XSLT document() function

Yesterday, someone asked a question about how to address issues of translating a code to a display name on one of the the Structured Documents workgroup's e-mail lists.  There's a technique that I've been using in XSLT for quite some time that allows me to access look-up tables very easily without having to embed translation logic in the XSLT stylesheet.  Before I describe the technique, I thought I'd share some of the various uses for it:
  1. Code translation.  Often you will have codes in a one code system that need to be translated into codes from another code system.  This technique allows you to look up the translation.  I've used this to translate local codes to codes from standard vocabularies for:
    1. Unit translation from ANSI+ to UCUM
    2. Local codes for problem severity to SNOMED codes for severity used in the HITSP C32
    3. Local codes for problem status to SNOMED codes for problem status.
    4. Local codes for problem type to SNOMED codes for problem type.
    5. Local codes for vital signs to LOINC codes for vital signs.
  2. Display name lookup.  Closely related to #1 above.  Often times, I have a standard code, but not the display name associated with it.  I can use this technique on small value sets (less that 1000 codes) to look up the display name (this is the use case for the problem presented on the list).
  3. Mapping from an identifier to a web service end point.  You can use this technique to map from:
    1. The home community ID to an XCA Web Service address
    2. A DICOM AE Title to a WADO Web Service endpoint.
  4. Validating against a dynamically changing rule, such as the validation of a code element against the current version of a vocabulary or value set.
The basic technique is to create (or have access to) an XML document resource which you will use in your stylesheet.  To declare this resource, you do something like the following:

<xsl:variable name="myDocument" select="document('mydocument.xml')"/>

This creates a variable which can be used in an XPath expression subsequently in your XML.  In the use case the querant posed, the issue was how to get a display name for a language code, to that the patients preferred language (expressed as a code) could be displayed in the UI.  The patient's language preferences are stored in the patient/languageCommunication/languageCode/@code attribute.

The following XSLT fragment shows a template that will return the display name of the patient language by looking it up through an XML document.

<xsl:variable name="langs" select="document('lang.xml')"/>
   ...
<xsl:template name='patientLanguage'>
  <!-- get the code -->
  <xsl:variable name='lang'
    select='//patient/languageCommunication/languageCode/@code'/>
  <xsl:variable name='mappedLang' select='$langs//language[@code=$lang]'/>
  <xsl:choose>
    <xsl:when test='$mappedLang'>
      <xsl:value-of select='$mappedLang/@displayName'/>
    </xsl:when>
    <xsl:otherwise>Unknown</xsl:otherwise>
  </xsl:choose>
</xsl:template>


The same technique can also be used to access a resource that is created dynamically through a RESTful web-server end-point.  I demonstrate one use of this technique in the post on Values Sets and Query Health.  


Another use for this technique is to check value-set conformance inside Schematron rules. If you have a requirement that code/@code come from a particular value set, you can write a rule that accesses a web resource based on the value set, as in the following example:


<rule context='*/cda:templateId[@root = templateIdentifier]'>
  ...
  <let name='code' value='cda:code/@code'/>
  <let name='valueSetDoc' value='document("https://example.com/RetrieveValueSet?id=1.2.840.10008.6.1.308")'/>
  <assert test='$valueSetDoc//ihe:Concept[@code = $code]'>
    The code/@code element must come from the XXX Value Set (OID: 1.2.840.10008.6.1.308)
  </assert>
</rule>


The use of external XML data files is a very powerful feature of XSLT.  Combining that use with dynamically created XML resources through web services makes it even more capable.