Monday, March 14, 2016

Replacing the root node on eConnect Requester GetEntity XML

By Steve Endow

If you are reading this, and if you actually understand the title of this post, you have my condolences, because it probably means that you are going through the punishment I'm currently going through of having to use eConnect Requester and GetEntity.

To be fair, eConnect Requester GetEntity isn't that bad.  But there is one seemingly tiny difference in the XML that GetEntity returns, and the XML that is generated by the eConnect Outgoing Service that is sent to MSMQ.

In the lovely eConnect integration that I'm currently updating, this is what the XML looks like when it is sent to MSMQ by the eConnect Outgoing Service:

< Sales_Transaction:root xmlns:Sales_Transaction="" >
< eConnect ACTION="2" Requester_DOCTYPE="Sales_Transaction" DBNAME="TWO" TABLENAME="SOP10100" DATE1="2016-03-10T15:51:34.117" SOPNUMBE="ORDST2244" SOPTYPE="2" >
< SO_Trans >

Notice the fancy root node, with the explicit namespace on the root node, and the xmlns namespace identifier (or whatever it's called).

This is what GetEntity returns:

< root >
  < eConnect ACTION="2" Requester_DOCTYPE="Sales_Transaction_RRD" DBNAME="TWO" TABLENAME="SOP10100" DATE1="2016-03-10T15:51:34.117" SOPNUMBE="ORDST2244" SOPTYPE="2" >
    < SO_Trans >

Notice that it only supplies the root node, with no namespace.

I originally hoped that wouldn't matter for my project, but as my luck would have it, the code I'm working with uses XSL to transform the eConnect XML into the XML format for the trading partner.  And that XSL will not work with the plain old "root" node.  And this XSL file is 350 lines long.

If you have ever worked with XSL, you can understand my desire to not want to touch it or make any changes.  Life is hard enough without XSL.

So, the path of least resistance was to modify the GetEntity root node to have it match the eConnect Outgoing MSMQ root node.

Great! Sounds like a plan!  Except I had no idea how to do that either.

It turns out, from what I could find, that the XMLDocument API does not have a supported means of changing the name of a node.

There might be a way to assign the namespace to an existing node, but I don't think I was able to find any good approaches to that, so I cobbled together a few samples of building an entirely new XML document, with a new root node, using the XDocument object.

It happened to be a good lesson, as I've never used XDocument before, and it is much easier to work with than XMLDocument.

So here's what I cobbled together after much trial and error.

public static string RenameRootNode(string xmlString)
        XDocument doc = XDocument.Parse(xmlString);
        XDocument newDoc = new XDocument();

        XNamespace ns = "";
        XElement newRoot = new XElement(ns + "root", 
            new XAttribute(XNamespace.Xmlns + "Sales_Transaction", ""));

        newDoc = new XDocument(newRoot);

        return newDoc.ToString();
    catch (Exception ex)
        throw ex;

I don't fully understand the strange nesting available with XDocument and XElement, but it works, and given my limited time, that is plenty good for me.  And again, there may be a way to assign the namespace to the document and the root node to produce equivalent results--if so, go for it.

But this function converts the GetEntity XML so that it matches what is generated by the eConnect Outgoing service, and my lovely XSL transform works properly with it.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

No comments: