We found out that Navision does not like empty nodes when receiving an XML message, as it places the empty elements in it’s inbound table with empty strings, which means that validation for these elements will fail. To solve this, we had to remove the empty elements from the message that is being sent to Navision. A custom pipeline component was created for this, with the following Execute method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /// <summary> /// IComponent.Execute method is used to initiate the processing of the /// message in this pipeline component. /// </summary> /// <param name="pc">Pipeline context.</param> /// <param name="inmsg">Input message.</param> /// <returns>Original input message.</returns> public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute( Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg) { // Remove empty elements from the message return RemoveEmptyElements(inmsg); } |
Now add the method that will remove the empty elements from the message that is being processed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /// <summary> /// Removes empty elements from a BizTalk message. /// </summary> /// <param name="pInMessage">The message being processed in the pipeline. </param> /// <returns>The message with the empty elements removed.</returns> private IBaseMessage RemoveEmptyElements(IBaseMessage pInMessage) { // To be able to use XSLT, we need the xsi namespace XmlDocument xmlDocument = AddXsiNameSpace(inmsg.BodyPart.Data) // Execute XSLT to do the removing of the empty elements Utils.RemoveEmptyNodesXSLT(xmlDocument); // Create a new body in the message pInMessage.BodyPart.Data = new MemoryStream(); // Save the message without the empty elements to the body xmlDocument.Save(pInMessage.BodyPart.Data); // Go to the start of the message, or it will not be processed pInMessage.BodyPart.Data.Position = 0; // Return the message without empty elements return pInMessage; } |
We use XSLT to find the empty elements, and remove these from the message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// <summary> /// Execute XSLT to remove empty elements from an XML message. /// </summary> /// <param name="xmlDocument">The XMLDocument with the message.</param> /// <returns>The XML message with the empty nodes removed.</returns> private static XmlDocument RemoveEmptyNodesXSLT(XmlDocument xmlDocument) { // Call XSLT to select the empty nodes var nodesToRemove = xmlDocument.SelectNodes("//*[count(child::node() | @*) =0]"); // Loop through all nodes that should be removed foreach (XmlNode nodeToRemove in nodesToRemove) { // Remove the empty node nodeToRemove.ParentNode.RemoveChild(nodeToRemove); } // Return the XMLDocument with the empty elements removed return xmlDocument; } |
Seeing how we need to have the xsi namespace to be able to use XSLT on the message, we will add this namespace to the message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /// <summary> /// Add the xsi namespace to a XML document. /// </summary> /// <param name="inputStream">Stream with the XML message data.</param> /// <returns>A XMLDocument with the xsi namespace.</returns> private static XmlDocument AddXsiNameSpace(Stream inputStream) { // Create a new NameTable NameTable nTable = new NameTable(); // Create a namespace manager XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(nTable); // Add the xsi namespace xmlnsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); // Used to parse the XML message XmlParserContext context = new XmlParserContext(null, xmlnsManager, null, XmlSpace.None); // Create new SML reader settings XmlReaderSettings settings = new XmlReaderSettings(); // Create a new XML reader that reads the XML message that was provided // and adds the xsi namespace XmlReader reader = XmlReader.Create(inputStream, settings, context); // Create a new XML document that will hold the new XML message XmlDocument xmldocument = new XmlDocument(); // Load the message into the document xmldocument.Load(reader); // Return the XMLDocument with the new XML message return xmldocument; } |