everest icon indicating copy to clipboard operation
everest copied to clipboard

Multiple Race Codes in CDA

Open LRFalk01 opened this issue 7 years ago • 3 comments

I'm having a difficult time getting this to work. I've reviewed the following pages: https://everest.codeplex.com/discussions/653908 http://te.marc-hi.ca/forums/default.aspx?g=posts&t=58

In my source XML I have the following:

<raceCode code="2106-3" displayName="White" codeSystem="2.16.840.1.113883.6.238" codeSystemName="Race &amp; Ethnicity - CDC"/>
<sdtc:raceCode code="2108-9" displayName="White European" codeSystem="2.16.840.1.113883.6.238" codeSystemName="Race &amp; Ethnicity - CDC"/>

Which fails to parse with the this error: System.Xml.XmlException: Can't parse 'raceCode' in namespace 'urn:hl7-org:sdtc'. The data does not appear to be an HL7v3 instance

This is my test that is blowing up:

        [TestMethod]
        public void ParseCcd()
        {
            var formatter = new XmlIts1Formatter();
            formatter.ValidateConformance = false;
            formatter.GraphAides.Add(new ClinicalDocumentDatatypeFormatter());
            formatter.RegisterXSITypeName("POCD_MT000040UV.Patient", typeof(MyPatientMultipleRaceCodes));
            formatter.Settings |= SettingsType.SuppressNullEnforcement | SettingsType.AlwaysCheckForOverrides;
            formatter.ValidateConformance = false;

            ClinicalDocument cda;
            using (var xr = new XmlStateReader(XmlReader.Create(@"C:\CDA_Tests\170.315_b1_toc_amb_ccd_r21_sample1_v8.xml")))
            {
                var result = formatter.Parse(xr, typeof(ClinicalDocument));
                cda = result.Structure as ClinicalDocument;
            }
        }

When I am rendering XML I have a different problem in that only one of the race codes is being assigned to the sdtc schema:

<sdtc:raceCode code="2106-3" codeSystem="2.16.840.1.113883.6.238" displayName="White" />
<raceCode code="2106-3" codeSystem="2.16.840.1.113883.6.238" displayName="White" />
<raceCode code="2108-9" codeSystem="2.16.840.1.113883.6.238" displayName="White European" />

Generated from this method:

        private MemoryStream RenderCda(ClinicalDocument cda)
        {
            XmlIts1Formatter fmtr = new XmlIts1Formatter();
            fmtr.RegisterXSITypeName("POCD_MT000040UV.Patient", typeof(MyPatientMultipleRaceCodes));
            fmtr.Settings |= SettingsType.SuppressNullEnforcement | SettingsType.AlwaysCheckForOverrides;
            fmtr.GraphAides.Add(new DatatypeFormatter());
            fmtr.ValidateConformance = false;

            // Prepare the output 
            var stream = new MemoryStream();
            XmlStateWriter xsw = new XmlStateWriter(XmlWriter.Create(stream, new XmlWriterSettings() { Indent = true }));
            xsw.WriteStartElement("ClinicalDocument", "urn:hl7-org:v3");
            xsw.WriteAttributeString("xmlns", "sdtc", null, "urn:hl7-org:sdtc");

            fmtr.Graph(xsw, cda);
            xsw.WriteEndElement();

            xsw.Flush();
            stream.Position = 0;

            return stream;
        }

I've been banging my head against this for quite awhile now. Any help would be welcomed.

LRFalk01 avatar Jun 06 '17 12:06 LRFalk01

I was able to get the parse to work with a custom build of Everest. I added the and clause on line 12 (code is from XmlIts1Formatter.cs):


        public IFormatterParseResult Parse(XmlReader r, Type t)
        {
            if (!(r is XmlStateReader))
                r = new XmlStateReader(r);

            // Initial state
            if (r.ReadState == ReadState.Initial)
                while (r.NodeType != XmlNodeType.Element)
                    r.Read();

            // Detect if we can parse this...
            if (r.NamespaceURI != "urn:hl7-org:v3" && r.NamespaceURI != "urn:hl7-org:sdtc")
                throw new XmlException(string.Format("Can't parse '{0}' in namespace '{1}'. The data does not appear to be an HL7v3 instance", r.LocalName, r.NamespaceURI), null);

            var resultContext = new XmlIts1FormatterParseResult(ResultCode.Accepted, null);
            resultContext.Structure = ParseObject(r, t, null, resultContext);
            return resultContext;
        }

LRFalk01 avatar Jun 06 '17 15:06 LRFalk01

I think the render issue is a bug where SET<T> only applies the NamespaceUri from the property attribute on the first item in the collection:

[Property(Name = "raceCode", PropertyType = PropertyAttribute.AttributeAttributeType.NonStructural, NamespaceUri = "urn:hl7-org:sdtc")]
public new SET<CE<string>> RaceCode { get; set; }

LRFalk01 avatar Jun 06 '17 17:06 LRFalk01

So, I was able to get this to work with a custom formatter:

        public class DlEverestFormatter : XmlIts1Formatter
        {
            protected override void GraphObject(XmlWriter s, IGraphable o, Type useType, IGraphable context, XmlIts1FormatterGraphResult resultContext)
            {
                var writer = (XmlStateWriter)s;
                if (writer.CurrentElement.Name == "raceCode" && useType.GetGenericTypeDefinition().FullName.Contains(".SET"))
                {
                    var raceCodes = (SET<CE<string>>)o;
                    var raceCodeCount = 0;
                    foreach (var raceCode in raceCodes)
                    {
                        if (raceCodeCount > 0)
                        {
                            s.WriteStartElement("raceCode", "urn:hl7-org:sdtc");
                        }

                        s.WriteAttributeString("code", raceCode.Code);
                        s.WriteAttributeString("codeSystem", raceCode.CodeSystem);
                        s.WriteAttributeString("displayName", raceCode.DisplayName);

                        raceCodeCount = raceCodeCount + 1;

                        if (raceCodeCount < raceCodes.Count)
                        {
                            s.WriteEndElement();
                        }
                    }
                    return;
                }

                base.GraphObject(s, o, useType, context, resultContext);
            }
        }

I also removed the NamespaceUri from my Patient class override RaceCode property. The override GraphObject takes care of setting the correct namespace for any raceCode past the first one. I will be doing the same for ethnicity which also has multiple in MU2015.

LRFalk01 avatar Jun 06 '17 19:06 LRFalk01