Tuesday, March 28, 2023

Translating CDA to FHIR: SNOMED CT Codes


One of the challenges in translating from CDA (or C-CDA) to FHIR is related to variations in how CDA and FHIR store complex SNOMED-CT codes using qualifiers.  As you might expect, these differences are especially significant when the concept being encoded uses the SNOMED CT Expressions

In CDA, these codes are stored using the ConceptDescriptor (CD) data type, and unpacks the concept using the Qualifier component of the concept description when the code is a SNOMED CT expression.  This is arguably a flaw in HL7 Version 3 standards, as the qualifier concept is variably expressed in SNOMED CT and other terminology systems differently through their own expression languages, and shouldn't be syntactically unpacked in the CD data type.  It's overengineering the terminology component to meet the needs of a data model, and overgeneralizing (in the favor of SNOMED) how this may be handled in other terminologies.

HL7 FHIR uses the CodableConcept data type, and doesn't unpack the expression (fixing this flaw).  If we take the SNOMED CT example provided at that link and shown below:

Example

And look at it in CDA, we would see:

<code xsi:type="CD" code="284196006" codeSystem="2.16.840.1.113883.6.96" 
      displayName="burn of skin">
    <qualifier>
        <name code="363698007" codeSystem="2.16.840.1.113883.6.96" displayName="finding site" />
        <value code="770850006" codeSystem="2.16.840.1.113883.6.96" 
               displayName="Skin structure of left index finger"/>
    </qualifier>
</code>

But in FHIR:

<code>
  <coding>
    <code value='284196006|burn of skin|:363698007|finding site|=770850006|Skin structure of left index finger|' 
          system='http://snomed.info/sct'/>
  </coding>
</code>
                    <!-- OR Better yet (IMNSHO*) -->
<code>
  <coding>
    <code value='284196006:363698007=770850006' system='http://snomed.info/sct'
          display='|burn of skin|:|finding site|=|Skin structure of left index finger|'/>
  </coding>
</code>
NOTE, the latter example is just a simplified version of the former without any display name values.

This use of SNOMED CT Expressions is advanced, and doesn't show up often in the real world, but when it does, it is a real challenge for implementers.

To convert from a SNOMED CT code with qualifiers in CDA to a SNOMED CT Code in FHIR, apply the following algorithm:

  1. Generate new nested <fhir:code>, <fhir:coding> and <fhir:code> elements.
  2. If there is a cda:code/@code attribute, generate a value attribute in the final fhir:code element as follows:
    1. Set fhir:code/@value attribute in FHIR to the value of cda:code/@code
    2. (Optional and legal, but not recommended): If there is a cda:code/@displayName attribute in the CDA, append "|" + @displayName + "|" to fhir:code/@value.  NOTE: This captures displayNames, which you should only trust from your own terminology service, and it also appends a string to fhir:code/@value which will complicate FHIR Search operations in most FHIR implementations.
    3. For each cda:qualifier element from SNOMED CT in the cda:code element. 
      1. Append ":" + cda:qualifer/cda:name/@code to fhir:code/@value
      2. Again, optional, legal and not recommended: append "|" + @displayName + "|" to fhir:code/@value
      3. Append "=" + cda:qualifer/cda:value/@code to fhir:code/@value
  3. If there isn't a code/@code attribute, generate an appropriate uncoded value in FHIR (possibly using null flavors depending on the IG).  NOTE: If there's NO @code, but there are cda:qualifier elements, this is bogus, and should be reported as a validation error on input, at least for SNOMED CT.  You can't qualify an uncoded value.
Some comments:
  1. SNOMED CT expressions allow display name values to be appended to a code between vertical bars | (we call these pipes in HL7 V2).  I don't recommend putting the display names into the code even though it's legal and semantically correct.  Pragmatically, it's going to cause your FHIR implementation to have problems in search.
    1. This is legal:
      <code value='284196006|burn of skin|:363698007|finding site|=770850006|Skin structure of left index finger|'  system='http://snomed.info/sct'/>
    2. But this is MUCH better:
      <code value='284196006:363698007=770850006'
            display='|burn of skin|:|finding site|=|Skin structure of left index finger|'
            system='http://snomed.info/sct'/>

  2. Don't trust display name values from external systems.  Use the display name values from your own, validated terminology service.

  3. Consider how incorporating qualifiers into codes will impact your search.  In general, qualifiers reflect refinement in SNOMED CT, which implies subclasses of the core code.  You might consider coding it twice, once without the qualifiers, and a second time with the qualifiers:
    <code>
      <coding>
    
        <code value='284196006' system='http://snomed.info/sct'
              display='burn of skin'/>
        <code value='284196006:363698007=770850006' system='http://snomed.info/sct'
    display='|burn of skin|:|finding site|=|Skin structure of left index finger|'/> </coding> </code>
    I like this better because a search for fhir/Condition?code=
    http://snomed.info/sct|284196006 is going to find what the end user expects, all Condition resources representing a burn of skin.

  4. If you go with #3 above, you may be concerned (and rightly so) about negation.  There are a couple of recommendations you might consider:
    1. Insert a human into the mix and ensure that qualifiers related to negation or other situations with explicit context are correctly interpreted in workflows that involve importing data from CDA into the patient chart.
    2. Read through and understand SNOMED CT documentation on this topic.
    3. Few systems today use SNOMED CT expressions.  Fewer yet use them with negation.  That doesn't mean you can safely ignore it. Make it an exceptional process in your conversions, AND don't try to automate processing it, just detect it and call for (human) assistance in interpretation.  The number of times that happens is likely be small enough to avoid user complaint, yet remain safe for patient care.  And note, my expert opinion does not excuse you from making your own risk assessments and code accordingly.

Keith

P.S. To make it even uglier, technically, the FHIR representation would also be legal in CDA, if about as rare as a snowball in Central Africa.

<code xsi:type="CD" value='284196006:363698007=770850006'
      displayName='|burn of skin|:|finding site|=|Skin structure of left index finger|'
      codeSystem="2.16.840.1.113883.6.96">
* IMNSHO = In My Not So Humble Opinion

0 comments:

Post a Comment