Convert your FHIR JSON -> XML and back here. The CDA Book is sometimes listed for Kindle here and it is also SHIPPING from Amazon! See here for Errata.

Wednesday, February 15, 2017

An XSLT Design Pattern (and not just for FHIR to CDA conversions)

I have a couple of XSLT design patterns that I've been using and improving over the past decade, which I pulled out again last night to do some FHIR to CDA transformations.  XSLT isn't what you'd call a strongly object oriented language, nor a strongly typed one.  However, the design patterns I used borrow from experiences I've had with strongly typed, object oriented languages such as Java.

The design pattern is a general one which I've used for a number of strongly typed schema to schema conversions.  FHIR to CDA is just one example.  V2 XML to CDA (or back) is another one, and I've also done this for CDA to ebXML (XDS related work), and at one point for CCR and CDA, even though I'd never really call CCR strongly typed.

The first design pattern is in how I define my transformations.  There are two ways in which you can call a template, and they have different benefits.  Sometimes you want to use one, and sometimes you want to use the other.  When going from one format to another in XML, usually there is a target element that you are trying to create, and one or more source elements you are trying to create it from.

My first method uses apply-templates.
<xsl:apply-templates select='...' mode='target-element-name'/>

You can also call apply-templates with parameters.
<xsl:apply-templates select='...' mode='target-element-name'>
  <xsl:with-param name='some-param' select='some-value'/>
</xsl:apply-templates>

This is pretty straight forward.  I use mode on my transformation templates for a variety of reasons, one of which is that it allows you to build transformation trees that the XSLT engine automates processing with.  More often that not, the name of the mode is the output element I'm targeting to generate.

The second method works more like a traditional function call, using call-template:
<xsl:call-template name='target-element-name'>
  <xsl:with-param name='this' select='the-source-element-to-transform'/>
  <xsl:with-param name='some-param' select='some-value'/>
</xsl:call-template>

Now, if the source element is always the same for a given target element (e.g., a FHIR address going to a CDA addr element), you create your actual template signature thus:

<xsl:template name='addr' mode='addr' match='address'>
  <xsl:param name='this' select='.'/>
   ...

Note that name and mode are the same.  What you want to create here is an <addr> element in CDA. The input you want to convert is a FHIR address element (I checked several dozen places, just about everywhere the Address datatype is used, it is always called address in FHIR resources).  So that explains the first line.  The name of the template, and its mode, identity what you are trying to create.

The second line is critical, and it has some serious impact on how you write your templates.  Instead of assuming a default context for your transformation, the <xsl:param name='this' select='.'/> sets up a parameter in which you can explicitly pass the transformation context, but which will implicitly use the current context if no such parameter is passed.  When you write your transformation, you have to be careful to use $this consistently, or you'll have some hard to find bugs, because sometimes it might work (e.g., when called using apply-templates), but other times not (e.g., when called using call-template).  It takes some diligence to write templates this way, but after a while you get used to it.

Here's the example for converting a FHIR Address to a CDA addr element.  It's pretty obvious:

<xsl:template name='addr' mode='addr' match='address'>
  <xsl:param name='this' select='.'/>
  <xsl:variable name='use'><xsl:choose>
    <xsl:when test='$this/use/@value="home"'>H</xsl:when>
    <xsl:when test='$this/use/@value="work"'>WP</xsl:when>
    <xsl:when test='$this/use/@value="temp"'>TMP</xsl:when>
  </xsl:choose></xsl:variable>
  <addr>
    <xsl:if test='$use!=""'>
      <xsl:attribute name='use'><xsl:value-of select='$use'/></xsl:attribute>
    </xsl:if>
    <xsl:for-each select='$this/line'>
      <streetAddressLine><xsl:value-of select='@value'/></streetAddressLine>
    </xsl:for-each>
    <xsl:for-each select='$this/city'>
      <city><xsl:value-of select='@value'/></city>
    </xsl:for-each>
    <xsl:for-each select='$this/state'>
      <state><xsl:value-of select='@value'/></state>
    </xsl:for-each>
    <xsl:for-each select='$this/postalCode'>
      <postalCode><xsl:value-of select='@value'/></postalCode>
    </xsl:for-each>
    <xsl:for-each select='$this/country'>
      <country><xsl:value-of select='@value'/></country>
    </xsl:for-each>
  </addr>
</xsl:template>

[There's a little XSLT shorthand nugget in the above transform, another design pattern I use a lot:
  <xsl:for-each select='x'> ... </xsl:for-each>

 is a much simpler way to say:
  <xsl:if test='count(x) != 0'> ... transform each x ... </xsl:if>

especially when x is a collection of items.]

Now, if you want to drop an address in somewhere, you can do something like this:
  <xsl:apply-templates select='address' mode='addr'/>

Or, you can also do it this way:
  <xsl:call-template name='addr'>
    <xsl:with-param name='this' select='$patient/address'/>
  </xsl:call-template>

Either works, and in developing large scale transformations, I often find myself using the same template in different ways.  The elegance of this design pattern in XSLT extends further when you have two or more source elements going to the same target element.

In that case, you have two templates with the same mode, but different match criteria.  AND, you have a named template.  Let's presume in the FHIR case, you want to map Resource.id and Resource.identifier to an id data type (it's not to far-fetched an idea, even if not one I would use). You then write:

  <xsl:template mode='id' match='id'>
    ...
  </xsl:template>
  <xsl:template mode='id' match='identifier'>
    ...
  </xsl:template>

  <xsl:template name='id'>
    <xsl:param name='this'/>
    <xsl:apply-templates select='$this' mode='id'/>
  </xsl:template>

And the final named template simply uses the match type to automatically select the appropriate template to use based on your input value.

Sometimes you want to create an output element but it isn't always called the same thing, even though it uses the same internal structure.  Using default parameters, you can set this up.  Let's look into example above.  Not EVERY id element is named id.  Sometimes in CDA the have a different name depending on what is being identified.  For example, in the CDA header, you have setId (in fact it's nearly the only case for id).  A more obvious case is code.  Most of the time, code is just code, but sometimes it's ____Code (e.g., priorityCode), but the general structure of a priorityCode (CE CWE [0..1]) is pretty much the same as for code (CD CWE [0..1]).  So, if you were going to convert a FHIR CodableConcept or Coding to a CDA CD/CE data type, you might use the same transformation.

  <xsl:template mode='code' match='code' name='code'>
    <xsl:param name='element' select='"code"'/>
    <xsl:element name='$name'>
      ...
    </xsl:element>
  </xsl:template>

You get the idea.  Usually, you want to generate <code>, and so you say nothing.  Sometimes you want to generate something different, and so you add a parameter.
  <xsl:call-template name='code'>
    <xsl:with-param name='this' select='$that/code'/>
    <xsl:with-param name='element' select='"priorityCode"'/>
  </xsl:call-template>

Remember you can also pass parameters using apply-templates, so this also works:
  <xsl:apply-templates select='$that/code'>
    <xsl:with-param name='element' select='"priorityCode"'/>
  </xsl:apply-templates>
  
Enough chatter, back to work.  HIMSS is only a couple of days away.

   - Keith

P.S.  I've missed being able to post while I've been heads down working towards HIMSS and the Interop showcase.  Hopefully I'll get more time when I get back.

Friday, January 20, 2017

FHIR Product Roadmap Jan 2017 update


This crossed my desk this morning via Grahame Grieve (HL7 Product Manager for FHIR).

   -- Keith




R3 plans
The FHIR project is presently finalising "STU3" (Standard for Trial Use, release 3). This 3rd major milestone is currently close to completion. We've been meeting in San Antonio this week to finalise ballot reconciliation, perform testing and quality activities, and we are now focusing on preparing the final publication package. Following our publication plan we expect to be publishing release 3 on or about Mar 20.
R4 plans
Once R3 is published, we will start working on release 4. The various committees that manage the different parts of Release 4 have been discussing their scope of work for R4, and planning their engagement and implementation activities to support that this week.
Some of the major things under consideration for Release 4:
<![if !supportLists]>·         <![endif]>Improvements across all domains
<![if !supportLists]>·         <![endif]>Cds-hooks integrated in FHIR Specification
<![if !supportLists]>·         <![endif]>Query language framework
<![if !supportLists]>·         <![endif]>Support for integrating research and clinical practice
The most significant change is that R4 is expected to be the first 'normative version'. It's important to understand what that means. We will continue to follow our overall maturity model, where content gradually matures through testing and implementation activities that demonstrate success in the real world. The end of the process is "normative" ("FMM level 6"), where the standard becomes stable, and breaking changes are no longer considered.
Only some portions of the specification are candidates for being normative. We are currently considering balloting the following parts of the specification as normative:
<![if !supportLists]>·         <![endif]>Infrastructure (API, data types, XML/JSON formats, conformance layer resources like StructureDefinition and ValueSet)
<![if !supportLists]>·         <![endif]>Administration (amongst others Patient, Organization, Practitioner)
We will continue to seek and receive comments about this. Some clinical resources may be considered, depending how implementation experience unfolds this year.
Overall planned R4 timeline:
<![if !supportLists]>·         <![endif]>Dec 2017: publish first draft of R4 for comment (finalise plans for normative sections)
<![if !supportLists]>·         <![endif]>Jan 2018: first R4 based connectathon(s)
<![if !supportLists]>·         <![endif]>April 2018: ballot R4
<![if !supportLists]>·         <![endif]>May – Sept 2018: ballot reconciliation
<![if !supportLists]>·         <![endif]>Oct 2018: publish FHIR R4
We will conduct a round of market consultations in Aug/Sept 2017 to seek comment on this timeline from the FHIR community.
Note that this timelines anticipates that we publish R4 in October irrespective of the outcome of the normative ballot. Anything that has not passed normative ballot will continue to published as STU. We are still working on preparation, quality and balloting processes to support the normative FHIR ballot.
Longer term, we anticipate following R4 with a roughly 18 month publication cycle, with increasing normative content.
Implementation Progress
FHIR is a specification for a common API for exchanging healthcare data between information systems. Any information system supporting the healthcare system can choose to implement the common API, and exchange data following the rules. FHIR enables a 'healthcare web' to exist, but doesn't actually create it.
HL7 is pleased to work on the FHIR specification with many hundreds of partners, who are all implementing the specification to exchange data in service of the healthcare needs to their enterprises, their customers, and, ultimately, patients. HL7 does not 'implement' the specification (other than various prototype/test services) – our partners and other healthcare services do.
Argonaut Project
One particularly important sub-group of the FHIR community is the Argonaut project, which is a joint project of major US EHR vendors to advance industry adoption of FHIR and we've had many questions about the Argonaut implementation timeline for EHR access. With regard to the Argonaut community:
<![if !supportLists]>·         <![endif]>The Argonaut STU2 specification for Common Clinical Data Set elements is close to being finalized and will be announced shortly.  The Argonaut STU3 specification for Provider Directory will be published after final balloting of STU3
<![if !supportLists]>·         <![endif]>Most Argonaut members who are certifying an API with ONC are using the Argonaut specification; most certifications are expected in Q1/Q2 2017
<![if !supportLists]>·         <![endif]>Software roll-outs have commenced — progress will vary depending on the vendor
<![if !supportLists]>·         <![endif]>It is presently unknown what the adoption rate by provider institutions will be — MU and MACRA in the US provide incentives to make a patient-facing API available by the end of 2017
<![if !supportLists]>·         <![endif]>Some of the Argonaut interfaces provide additional functionality not yet described in the Argonaut specification, but there is considerable appetite for additional services beyond what is currently available. The Argonaut project will be making announcements about its future plans shortly which will be announced in a press release, through collaboration channels, and at www.argonautproject.org

Tuesday, January 17, 2017

Semper et semper ascendens deinceps

Always and always riding forward.  If you remember the original reference, you know what's coming next.

I had the honor today of having Wes Rishel in my CDA, XDS and FHIR class today.  Wes was the guy that co-opted my skills for his workgroup (Attachments), and for HL7 as a whole.  He has had an outstanding career as an Analyst for Gartner, and is a past co-chair of the HL7 Organization.  Now retired, Wes is doing some side consulting work with his rural health exchange.  He's one of the examples that I hold up before me that tells me I'll never need to retire from doing what I love.

Ed Hammond is another young fellow at HL7 who's stamina is outstanding.  Ed has been a mentor to many in HL7 and I count myself also among his mentees.  Ed teaches Informatics at  Duke University, has the longest tenure on the HL7 Board of any known person, having reached the pinacle of leadership at HL7 as Cochair Emeritus.  He's been recognized in many other forums (AMIA for example).  He's so influentially involved in so many places I want to make a Cards against Humanity cards that says "It wouldn't be the same ______ without Ed Hammond."

Both Wes and Ed are hereby inducted into the 2017 class of the Lords and Ladies of the Ad Hoc Harley.


Wes Rishel and Ed Hammond
Semper et semper ascendens deinceps
(ever and ever riding forward)
  
And now you both can also add LLAHH (Ladies and Lords of the Ad Hoc Harley) after your names if you so wish.





P.S  Pictures don't lie. Ed never ages. He looks the same as he did in 1990.

Sunday, January 15, 2017

The FHIR $relevant Query

So I finally got my implementation of the "$everything" query working on my HAPI Server.  I started this at the FHIR Connectathon whilst waiting for people to hit my server.  It was in response to a need I had to generate a f***-ton of sample data in FHIR for testing and documentations.

Basically I have a code generator that reads FHIR profiles.  It's smart enough to assist me in producing some cool stuff.  After I got done, I wondered what I should do with it.

Given that this week we are closing in on the Relevant and Pertinent ballot, I think I'll just throw it away (just kidding ... I'll keep it around for debugging purposes), but I think the next query I build will be the "$relevant" one.

Here's my initial take on what that might look like:
Allergies = any active allergies.
Conditions = any that have been active in the last 30 days
Medications = any that have been active in the last 30 days, or any that were discontinued for lack of effect or toleration.
Labs = Most recent result of any lab type in last year.
Procedures = last year history and any currently scheduled
Vitals = most recent set
Immunizations = Last year for non-pediatric patients, otherwise all.
Encounters = any upcoming and last 90 days.

What's missing here is probably the most recent clinical impression.

-- Keith

Saturday, January 14, 2017

Healthcare Standards Blog in Feedspot Top 100 Healthcare Blogs


This showed up in my inbox yesterday.  I reposted here with Anuj's permission.

---------------------------------------------

Hi Keith,

My name is Anuj Agarwal. I'm Founder of Feedspot.

I would like to personally congratulate you as your blog Healthcare Standards  has been selected by our panelist as one of the Top 100 Healthcare Blogs on the web.


I personally give you a high-five and want to thank you for your contribution to this world. This is the most comprehensive list of Top 100 Healthcare Blogs  on the internet and I'm honored to have you as part of this!

Also, you have the honor of displaying the following badge on your blog. Use the below code to display this badge proudly on your blog.


Best,
Anuj

 Anuj Agarwal
 Founder, Feedspot
 Email: anujagarwal@feedspot.com
 Linkedin . Twitter


Friday, January 13, 2017

Faking it with the FHIR Basic Resource

The FHIR team created the Basic resource to support extensibility.  It works great except that HAPI only supports one read() method for each resource, and sometimes you have more than one thing for which you need to extend basic. For my needs, I've been looking at Account and Transaction (representing either a payment or a charge).  So, how do I use Basic to implement these non-FHIR "resources".

What I finally worked out was to use a named operation.

With one set of operation parameters, the operation responds as for FHIR Read and is idempotent.
With another set of parameters, it responds as for a FHIR Search (and also is idempotent).
With another set it would respond as for Create/Update, where the distinction between Create and Update merely depends on whether the resource included in the POST/PUT contains an identifier or not.

This gives the user of the profiled Basic resource an experience that is pretty close to what they would get with a true FHIR Resource (and consequently makes it easier to adopt new resources that have been profiled in this fashion).

   Keith

Thursday, January 12, 2017

What is it?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:cda='urn:hl7-org:v3' 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.0">
  <xsl:template match="/|cda:*|@xsi:type|text()|@*">
    <xsl:copy>
      <xsl:apply-templates select="cda:*|@*|text()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

What is this small but useful beast?