Friday, May 31, 2013

Emitting XML Comments from Everest

A great question came to me the other day. How does one pretty-up the XML output generated by Everest so that humans can read the XML? Of course there are the old tricks of indentation and formatting the output however that only gets us so far.
Wouldn’t it be great if Everest had the capacity to emit comments in the XML instances. Sadly this isn’t a use case for vanilla Everest however there is a way to easily do this in the upcoming 1.2 release of Everest (being released on June 5th BTW).
Lets say I want to emit a comment that annotates the <acceptAckCode> element, something like this:
<?xml version="1.0" encoding="utf-8"?>
<PRPA_IN101301UV02 ITSVersion="XML_1.0" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hl7-org:v3">
  <id root="F043D3BF-02C4-48BF-8C7E-6FFEE7D75B52" />
  <creationTime value="20130531171954.939-0400" />
  <interactionId root="2.16.840.1.113883.1.18" extension="PRPA_IN101301UV02" />
  <processingCode code="T" />
  <processingModeCode code="A" />
  <!--The acknowledgement code—>
  <acceptAckCode code="AL" />
</PRPA_IN101301UV02>
The way I would do this is to add an extension method to IGraphable to allow users to add commnents: public static class CommentExtension
{

    private static List<KeyValuePair<IGraphable, String>> s_comments = new List<KeyValuePair<IGraphable, string>>();
    private static Object s_syncLock = new object();
    public static void AddComment(this IGraphable me, string comment)
    {
        lock (s_syncLock)
                s_comments.Add(new KeyValuePair<IGraphable, String>(me, comment));
    }

    public static string GetComment(this IGraphable me)
    {
        return s_comments.Find(o=>o.Key == me).Value;
    }
}

We can then extend the XmlIts1Formatter and override the WriteElementUtil method to emit the comment added prior to serializing the element:
public class XmlIts1FormatterWithComments : XmlIts1Formatter
{
    public override void WriteElementUtil(System.Xml.XmlWriter s,
               string elementName,
               MARC.Everest.Interfaces.IGraphable g,
               Type propType,
               MARC.Everest.Interfaces.IGraphable context,
               XmlIts1FormatterGraphResult resultContext)
    {
        String comment = g.GetComment();
        if (comment != null)
            s.WriteComment(comment);
        base.WriteElementUtil(s, elementName, g, propType, context, resultContext);
    }
}

Then, using this new formatter we can simply add the comment and format!


PRPA_IN101301UV02 test = new PRPA_IN101301UV02(
    Guid.NewGuid(),
    DateTime.Now,
    PRPA_IN101301UV02.GetInteractionId(),
    ProcessingID.Training,
    ProcessingMode.Archive,
    AcknowledgementCondition.Always);
test.AcceptAckCode.AddComment("The acknowledgement code");

var formatter = new XmlIts1FormatterWithComments();
formatter.GraphAides.Add(new DatatypeFormatter());
formatter.Graph(Console.OpenStandardOutput(), test);
Console.ReadKey();

Hope that helps anyone else with the same problem!