CDA in Everest
justin.fyfe1
#1 Posted : Friday, July 15, 2011 12:53:15 PM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Well,

As promised, we've been working hard on Everest 1.0 and this includes support for CDAr2. Anyone who is interested in trying the CDAr2 functionality with Everest 1.0 will need to get a snapshot version from the team (email me) and will need to have the POCD_MT000030.mif and POCD_MT000040UV.mif files. After you have these two MIFs, just copy them into a directory with DEFN=UV=IFC=1.9.3.coremif, DEFN=UV=RIM=0229R1.coremif and DEFN=UV=VO=913-20091020.coremif and run the following command:

gpmr --renderer=RIMBA_CS -c -o C:\temp\cs --rimbapi-gen-vocab=true --rimbapi-target-ns=MARC.Everest.RMIM.UV.CDAr2 --optimize=true --combine=true C:\sources\mif\cdar2\*.*mif --rimbapi-compile=true --rimabpi-dllonly=true

After a few seconds GPMR will spit out a DLL called MARC.Everest.RMIM.UV.CDAr2.dll . Now you're ready for some code, create a project and add the references to the CDAr2 assembly. The example below creates a very basic CDA (not at all conformant but good for illustration purposes):

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MARC.Everest.DataTypes;
using MARC.Everest.RMIM.UV.CDAr2.POCD_MT000040UV;
using MARC.Everest.RMIM.UV.CDAr2.Vocabulary;
using System.IO;

namespace CDATest
{
    class Program
    {
        static void Main(string[] args)
        {

            ClinicalDocument myCDA = new ClinicalDocument(
                new II("1.2.3.4.5", "c3049"),
                "20394-3",
                DateTime.Now,
                x_BasicConfidentialityKind.N_,
                new RecordTarget() { NullFlavor = MARC.Everest.RMIM.UV.CDAr2.Vocabulary.NullFlavor.NoInformation },
                new Author() { NullFlavor = MARC.Everest.RMIM.UV.CDAr2.Vocabulary.NullFlavor.NoInformation },
                new Custodian() { NullFlavor = MARC.Everest.RMIM.UV.CDAr2.Vocabulary.NullFlavor.NoInformation },
                new Component2(false)
            ) {
                    Title = "Hello World!"
            };

            MARC.Everest.Formatters.XML.ITS1.Formatter fmtr = new MARC.Everest.Formatters.XML.ITS1.Formatter();
            fmtr.ValidateConformance = false;
            fmtr.GraphAides.Add(typeof(MARC.Everest.Formatters.XML.Datatypes.R1.Formatter));
            fmtr.GraphObject(Console.OpenStandardOutput(), myCDA);
            Console.ReadKey();
        }
    }
}


Everest will generate the following XML for you:

Code:

<?xml version="1.0" encoding="utf-8"?>
<ClinicalDocument classCode="DOCCLIN" moodCode="EVN" xmlns="urn:hl7-org:v3">
  <id root="1.2.3.4.5" extension="c3049" />
  <code code="20394-3" />
  <title representation="TXT" mediaType="text/plain" language="en-US">Hello World!</title>
  <effectiveTime value="20110715132512.977-0400" />
  <confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25" />
  <recordTarget p2:nil="true" nullFlavor="NI" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
  <author p2:nil="true" nullFlavor="NI" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
  <custodian p2:nil="true" nullFlavor="NI" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
  <component typeCode="COMP" contextConductionInd="false" />
</ClinicalDocument>


Have fun :)
BenekDlugonogi
#2 Posted : Saturday, February 15, 2014 4:28:55 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
Hi,

Can you tell me where you can find POCD_MT000030.mif file?
justin.fyfe1
#3 Posted : Saturday, February 15, 2014 4:33:52 AM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hi,

Apologies this post is a little old, if you just want to created CDA documents with Everest you can use the built in DLL files now. If you want the PICD_MT000040.MIF you'll need to generated it from the HL7v3 standard. To do this you'll need to download the zip file for NE2008/2010 from hl7.org and then the hl7v3 generator from gforge.hl7.org . You can extract the POCD_MT000040UV.vsd file from the NE2008 bundle and run the v3 generator on it.

This will produce a couple of files, but what you want is just the MIF file ;) .. Also note this isn't too trivial of a task to perform..
BenekDlugonogi
#4 Posted : Saturday, February 15, 2014 4:40:55 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
thanks for the reply :)

I am trying to understand how can I used Everest Frameowrk to generate CDA documents :-(
justin.fyfe1
#5 Posted : Saturday, February 15, 2014 4:43:55 AM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
No problem.

There is a DLL in the installer named MARC.Everest.RMIM.UV.CDAr2 which will contain the necessary models. One of the samples included also generates a minimal CDA to show how to get the hang of it. There are also lots of good posts on the forums which have some good tricks for generating based on what others have done.

Cheers
-Justin
BenekDlugonogi
#6 Posted : Saturday, February 15, 2014 4:53:41 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
I did not notice the directory with dlls

Now (I think) makes it more difficult question: In Poland we have implemention guide that extends the standard CDA with own namespace. As I understand I have to do hocus-pocus MIF files to generate extended library?

Ok i found this
justin.fyfe1
#7 Posted : Saturday, February 15, 2014 5:07:07 AM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Ah yes, that post will be very helpful for adding extended attributes. The only problem is that the formatter always outputs elements from the class in the urn:hl7-org:v3 namespace, so if your extensions are outside that namespace it will not work.

We're currently working on the 1.4 version (which is the 1.3 branch) which will address this issue. I can take a look to see if it could be backport ed to 1.2 (or simply implemented in 1.2).

Cheers
BenekDlugonogi
#8 Posted : Saturday, February 15, 2014 5:24:47 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
Unfortunately, our "geniuses" added xmlns:extPL="http://www.csioz.gov.pl/xsd/extPL/r1" namespace.

It cheers to solve this problem. If you are interested at (here) is our extension file extPL_r1.xsd and examples (8.xml)

Too bad I do not have the knowledge to help :-( Or maybe somehow I can?
BenekDlugonogi
#9 Posted : Saturday, February 15, 2014 1:45:50 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
I spent the day with Everest (trunk). I wanted to add support for external namespaces.
Could you comment on if it well done? What changed and maybe everything makes no sense.

Attach patches and test program. The generated XML file is great in our conditions.

Code:
...


Code:
...


Code:
...
justin.fyfe1
#10 Posted : Saturday, February 15, 2014 11:06:01 PM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hi,

Thanks for the analysis! You actually landed on the same solution we used in 1.3 which I am happy to say that I've ported to 1.2 branch. I have been travelling and wrote an update on the plane which should be integrated by later tomorrow. The only difference is we used NamespaceUri instead of Namespace on the property attribute ;)

On another note, we're investigating moving Everest over to Codeplex in May/June which will make contributions much easier as well.
BenekDlugonogi
#11 Posted : Sunday, February 16, 2014 5:05:44 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
Superb

But after i added parameter to WriteElementUtil i sometimes have problem with magic compilation :-(: "No overload for method 'WriteElementUtil' takes '6' arguments"

Code:

MARC.Everest.Exceptions.FormatterCompileException was unhandled
  IsTransient=false
  Message=A compile exception has occured during creation of the formatter assembly
  Source=MARC.Everest.Formatters.XML.ITS1
  TempFile=""
  StackTrace:
       at MARC.Everest.Formatters.XML.ITS1.CodeGen.CodeGenFormatter.CreateFormatterAssembly(Type[] rmimTypes, List`1 aides, Boolean generateDeep) in d:\Projects\HL7\Everest-git\MARC.Everest.Formatters.XML.ITS1\CodeGen\CodeGenFormatter.cs:line 279
       at MARC.Everest.Formatters.XML.ITS1.XmlIts1Formatter.BuildCache(Type[] t) in d:\Projects\HL7\Everest-git\MARC.Everest.Formatters.XML.ITS1\XmlIts1Formatter.cs:line 934
       at MARC.Everest.Formatters.XML.ITS1.XmlIts1Formatter.<GraphObject>b__19(Object state) in d:\Projects\HL7\Everest-git\MARC.Everest.Formatters.XML.ITS1\XmlIts1Formatter.cs:line 1377
       at MARC.Everest.Threading.WaitThreadPool.DoWorkItem(WorkItem state) in d:\Projects\HL7\Everest-git\MARC.Everest\Threading\WaitThreadPool.cs:line 208
       at MARC.Everest.Threading.WaitThreadPool.DispatchLoop() in d:\Projects\HL7\Everest-git\MARC.Everest\Threading\WaitThreadPool.cs:line 165
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:
justin.fyfe1
#12 Posted : Sunday, February 16, 2014 1:52:31 PM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hi,

I will commit the code that we've updated to the 1.2 branch and place merge it into trunk later today and will post an update when it is done (it takes a few hours for our CI server to run all the unit tests in the MARC.Everest.Test project).

I will also post a new installer for version 1.2.13 which contains this functionality as well.

Cheers
-Justin
justin.fyfe1
#13 Posted : Sunday, February 16, 2014 10:45:40 PM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hi,

I have committed the changes to the SVN. You should be able to extend a base class and add custom elements from another namespace via the NamespaceUri property attribute parameter.

Cheers
-Justin
BenekDlugonogi
#14 Posted : Monday, February 17, 2014 1:54:51 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
I can still see problems, but as I reach for solutions that will let you know. I will also attempt to write tests.

How would be best to give you my changes?
BenekDlugonogi
#15 Posted : Monday, February 17, 2014 3:34:45 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
I did tests that represent our cases (at least I think so)

http://pastebin.com/PLKXsLHQ

Certainly I noticed:
a) should be able to add namespaces at root element. ("XML" would able to use convention <custom:myelement>...</custom:myelement>)
b) inheritance ClinicalDocument should be performed by adding the xsi:type.

Have you got idea how to solve b).

PS Sorry for the extra work :-(
justin.fyfe1
#16 Posted : Monday, February 17, 2014 4:56:53 PM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hi,

The challenge with generating a custom xsi:type at the root is that (from Everest's perspective) you're formatting an object and Everest doesn't know it is in fact overridden (it just thinks everyone is expecting your implementation of ClinicalDocument). That being said, it is possible to do what you're asking for, you just need to write a little bit of code to do it. I've been able to generate this CDA:

Code:

<cda:ClinicalDocument xmlns:extPL="http://www.csioz.gov.pl/xsd/extPL/r1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="extPL:ClinicalDocument" classCode="DOCCLIN" moodCode="EVN" xmlns:cda="urn:hl7-org:v3">
  <extPL:pertientInformation typeCode="PERT">
    <cda:templateId root="1.13.2.3" />
    <extPL:coveragePlan classCode="COV" moodCode="EVN">
      <extPL:code code="PUBLICPOL" codeSystem="2.16.840.1.113883.11.19350">
        <cda:qualifier inverted="false">
          <cda:name code="RLEKUD" codeSystem="1.2.3.4" displayName="Refundacja ..." />
          <cda:value code="IB" codeSystem="1.2.3.4" />
        </cda:qualifier>
      </extPL:code>
    </extPL:coveragePlan>
  </extPL:pertientInformation>
</cda:ClinicalDocument>


By manually writing the root elements you seek, any further overriding should be handled automatically. The only issue would be the prefixes on XSI type which are not handled automatically in the current Everest implementation, however you can override this behavior by inheriting a custom XmlIts1Formatter (which isn't too hard). Here is the code I used to generate the above CDA instance:

Code:

PLClinicalDocument cda = new PLClinicalDocument();
var pi = new PertinentInformation() { TemplateId = LIST<II>.CreateList(new II("1.13.2.3")) };
pi.CoveragePlan = new CoveragePlan(new CD<String>("PUBLICPOL", "2.16.840.1.113883.11.19350"));
pi.CoveragePlan.Code.Qualifier = LIST<CR<String>>.CreateList(
    new CR<String>(
        new CV<String>("RLEKUD", "1.2.3.4", null, null, "Refundacja ...", null),
        new CD<String>("IB", "1.2.3.4")
    )
);
cda.PertinentInformation.Add(pi);

XmlIts1Formatter xftr = new XmlIts1Formatter();
xftr.GraphAides.Add(new ClinicalDocumentDatatypeFormatter());
xftr.ValidateConformance = false;
xftr.RegisterXSITypeName("POCD_MT000040UV.ClinicalDocument", typeof(PLClinicalDocument));
xftr.Settings |= SettingsType.AlwaysCheckForOverrides;

using (FileStream ms = File.Create("e:\\temp\\output.xml"))
{
    using (XmlStateWriter xw = new XmlStateWriter(XmlWriter.Create(ms)))
    {
        xw.WriteStartElement("cda", "ClinicalDocument", "urn:hl7-org:v3");
        xw.WriteAttributeString("xmlns", "extPL", null, "http://www.csioz.gov.pl/xsd/extPL/r1");
        xw.WriteAttributeString("xmlns", "xsi", null, XmlIts1Formatter.NS_XSI);
        xw.WriteAttributeString("xsi", "type", XmlIts1Formatter.NS_XSI, "extPL:ClinicalDocument");

        xftr.Graph(xw, cda);
        xw.WriteEndElement();
    }


Some samples of the classes which I created to construct this CDA:

Code:

[Structure(Name = "ClinicalDocument", IsEntryPoint = true, Model = "POCD_MT000040UV")]
public class PLClinicalDocument : MARC.Everest.RMIM.UV.CDAr2.POCD_MT000040UV.ClinicalDocument
{
    /// <summary>
    /// Default ctor for clinical document
    /// </summary>
    public PLClinicalDocument() : base()
    {
        this.PertinentInformation = new List<PertinentInformation>();
    }

    /// <summary>
    /// Ctor for required elements
    /// </summary>
    public PLClinicalDocument(II id, CE<string> code, TS effectiveTime, CE<x_BasicConfidentialityKind> confidentialityCode, RecordTarget recordTarget, Author author, Custodian custodian, Component2 component) :
        base(id, code, effectiveTime, confidentialityCode, recordTarget, author, custodian, component)
    {
        this.PertinentInformation = new List<PertinentInformation>();

    }

    /// <summary>
    /// Ctor for all elements
    /// </summary>
    public PLClinicalDocument(II id, CE<string> code, ST title, TS effectiveTime, CE<x_BasicConfidentialityKind> confidentialityCode, CS<string> languageCode, II setId, INT versionNumber, TS copyTime, RecordTarget recordTarget, Author author, DataEnterer dataEnterer, Informant12 informant, Custodian custodian, InformationRecipient informationRecipient, LegalAuthenticator legalAuthenticator, Authenticator authenticator, Participant1 participant, InFulfillmentOf inFulfillmentOf, DocumentationOf documentationOf, RelatedDocument relatedDocument, Authorization authorization, Component1 componentOf, Component2 component)
        : base(id, code, title, effectiveTime, confidentialityCode, languageCode, setId, versionNumber, copyTime, recordTarget, author, dataEnterer, informant, custodian, informationRecipient, legalAuthenticator, authenticator, participant, inFulfillmentOf, documentationOf, relatedDocument, authorization, componentOf, component)
    {
        this.PertinentInformation = new List<PertinentInformation>();
    }


    /// <summary>
    /// Gets or sets the pertinent information class
    /// </summary>
    [Property(Name = "pertientInformation", NamespaceUri = "http://www.csioz.gov.pl/xsd/extPL/r1", Conformance = PropertyAttribute.AttributeConformanceType.Optional, PropertyType = PropertyAttribute.AttributeAttributeType.Traversable, SortKey = 99)]
    public List<PertinentInformation> PertinentInformation { get; set; }
}

[Structure(Name = "CoveragePlan", NamespaceUri = "http://www.csioz.gov.pl/xsd/extPL/r1", Model = "POCD_MT000040PL")]
public class CoveragePlan : InfrastructureRoot
{
    /// <summary>
    /// Default CTOR for document
    /// </summary>
    public CoveragePlan()
    {
        this.ClassCode = "COV";
        this.MoodCode = ActMoodEventOccurrence.Eventoccurrence;
    }

    public CoveragePlan(CD<String> code)
        : this()
    {
        this.Code = code;
    }

    [Property(Name = "classCode", Conformance = PropertyAttribute.AttributeConformanceType.Mandatory, PropertyType = PropertyAttribute.AttributeAttributeType.Structural, SortKey = 1, FixedValue = "COV")]
    public CS<String> ClassCode { get; set; }

    [Property(Name = "moodCode", Conformance = PropertyAttribute.AttributeConformanceType.Mandatory, PropertyType = PropertyAttribute.AttributeAttributeType.Structural, SortKey = 2, FixedValue = "EVN")]
    public CS<ActMoodEventOccurrence> MoodCode { get; set; }

    [Property(Name = "code", Conformance = PropertyAttribute.AttributeConformanceType.Mandatory, NamespaceUri = "http://www.csioz.gov.pl/xsd/extPL/r1", PropertyType = PropertyAttribute.AttributeAttributeType.NonStructural, SortKey = 4)]
    public CD<String> Code { get; set; }
}



I believe this would solve both your issues.
1 user thanked justin.fyfe1 for this useful post.
BenekDlugonogi on 2/18/2014(UTC)
BenekDlugonogi
#17 Posted : Tuesday, February 18, 2014 1:38:13 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/15/2014(UTC)
Posts: 9
Points: 30

Thanks: 1 times
Was thanked: 0 time(s) in 0 post(s)
Thanks a lot

I updated unit test at pastebin http://pastebin.com/PLKXsLHQ . 1 test is failing. Could you look at the test (ClinicalDocumentInheritanceWithCustomType)?

It will be passed when i change this:

Code:
--- a/MARC.Everest.Formatters.XML.ITS1/XmlIts1Formatter.cs
+++ b/MARC.Everest.Formatters.XML.ITS1/XmlIts1Formatter.cs
@@ -1142,7 +1142,7 @@ namespace MARC.Everest.Formatters.XML.ITS1
                 string xsiType = r.GetAttribute("type", NS_XSI);
                 // Is this model / type registered somewhere ?
                 if ((this.Settings & SettingsType.AlwaysCheckForOverrides) != 0 && xsiType == null &&
-                    !typeof(ANY).IsAssignableFrom(useType))
+                    !typeof(ANY).IsAssignableFrom(useType) && r.NamespaceURI == "urn:hl7-org:v3")
                     xsiType = string.Format("{0}.{1}", this.GetModelName(useType), typeName);

                 if (xsiType != null)


I do not know is this the correct fix.
justin.fyfe1
#18 Posted : Tuesday, February 18, 2014 10:50:46 AM(UTC)

Rank: Administration

Medals: Mobile Tech Grasshopper: Mobile Tech GrasshopperHealth Informatics MVP

Groups: Registered, Administrators
Joined: 7/22/2010(UTC)
Posts: 96
Points: 297
Man
Location: Hamilton, ON

Thanks: 2 times
Was thanked: 17 time(s) in 17 post(s)
Hello,

Thanks for the test, you're right that it has outlined a problem with the parsing of XSI type names. I am working on a solution for this as ParseXSITypeName doesn't take into account namespaces (neither did CreateXSITypeName).

I have updated the XmlIts1Formatter to behave properly and will commit the code to the 1.2 branch. The good news is the formatter will now properly handle xsi:type="ns:Type".

Cheers
-Justin
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

SoClean Theme By Jaben Cargman (Tiny Gecko)
Powered by YAF 1.9.4 | YAF © 2003-2010, Yet Another Forum.NET
This page was generated in 0.258 seconds.