none
How to handle messages (XMLs) without namespaces with Biztalk ESB? (an XPath query error?)

    Question

  • First, I have used the Biztalk ESB Add and Remove namespace pipeline component to do the job. However, it seems that they didn't fit the requirement. I searched this forum and it seems that for my particular case, I have to develop my own custom pipeline component. But, I just want to be sure before hand.

    This is what I have done:

    I created a custom pipeline to automate the process of adding the namespace. To make everything easier, I used the ESB Toolkit pipeline components, namely ESB Remove Namespace and ESB Add Namespace (available from $ESB_INSTALL_DIR\Microsoft.Practices.ESB.PipelineComponents.dll). I use these components in my receive pipeline decode stage. The remove namespace pipeline component removes the namespace (if one exists) from the incoming XMLs and then the ESB Add Namespace pipeline component adds new namespace based on XPath queries. I added the "default" XML disassembler and party resolution components from the pipeline toolbox to my custom pipeline. Compile and deploy, I used it in my receive location. I'm not sure why my custom pipeline is not working without those two components (XML disassembler and party resolution components). Anyone can explain it?

    Now, the requirements: As per the client specs, I could only use one receive location for 3 types of XMLs (3 different schemas). Among the schemas, 2 of them don't have any namespace. Therefore, I have to add the namespace on-the-fly in the receive pipeline. That's what I did above.

    The problem is: I tried to detect those three different XMLs by using an XPath query to unique child element in the XMLs. I did this by querying the child element name. Unfortunately it always failed with "End element" exception. I used the local-name() and name() XPath query function but none of them seems working correctly. This is the details of the XPath query: 

    /PT02000009/*[7][local-name()]

    Note: The root element name is PT02000009 and I tried to query the local-name() of the seventh element.

    I tested my XPath query with XPath Visualizer and the element is correctly selected. However, upon giving the XPath query to the ESB Add Namespace pipeline component's XPath property. It failed at runtime with "End element" exception on XMLs that contains the said seventh element.

    After several days trying I suppose that the ESB Add Namespace pipeline component cannot evaluate local-name() and name() XPath queries correctly. I believe I should make my own custom Add namespace pipeline component.

    Saturday, June 18, 2011 4:53 AM

Answers

  •  

    Hi Tomasso,

    I forgot to mention that I have tried the XPath expression that you suggested.

    Anyway, I finally decided to create a custom component based-on the Biztalk Enterprise Adapter Pipeline component sample. I'm half way to finish it. I decided to just detect whether a distinctive component is present, such as this in XPath:

    descendant::PT02000009/*[local-name()='LampiranIC']

    I planned to use this C# code snippet ( a part of the pipeline component modification):

    XPathNodeIterator nodeset = navigator.Select("descendant::PT02000009/*[local-name()='LampiranIC']");

                Console.WriteLine("nodeset.count = {0}", nodeset.Count);

                if (nodeset.Count > 0)
                {
                    Console.WriteLine("Element detected.");
                }
                else
                {
                    Console.WriteLine("Element __not__ detected.");
                }

     

    Later, the nodeset count could be used to return the detection result. The result will be used as parameter to set the namespace value in a configurable pipeline component parameter.

    Another function that I'm currently investigating is the XmlNode.SelectSingleNode(). If this function returns null, it means the element absent. This should be easy to use to replace the Select() function above.

     

    ========== edit (last status)=================

    I finally made a custom pipeline component which uses the XmlNode.SelectSingleNode() function to detect the type of incoming XML and set the namespace accordingly. It works :-). The custom pipeline component is based on the Microsoft BizTalk Adapters for Enterprise Applications Pipeline Component source code. A heavy modification on the base code was carried out to meet the spec. But, overall it works as expected.



    Monday, June 20, 2011 7:04 AM

All replies

  • I forgot to mention that the example in the ESB Toolkit samples and its related documentation only mention the usage of ESB Add namespace pipeline component to detect the value of a child element. After much testing, it seems to me that this particular component only able to query child element/node values.
    Saturday, June 18, 2011 5:33 AM
  • Hi,

    Maybe you can change the xpath expression?

    If the root element sometimes has a namespace you also have to use "[local-name()='']" for the root element

    Example: /*[local-name()='PT02000009']/node()[7]

    If the name of the root element changes you can select a node by the following xpath expression:

    //*[1][local-name()='MyNode']

     

    greetings,

     

    Tomasso Groenendijk

    Sunday, June 19, 2011 10:26 AM
  •  

    Hi Tomasso,

    I forgot to mention that I have tried the XPath expression that you suggested.

    Anyway, I finally decided to create a custom component based-on the Biztalk Enterprise Adapter Pipeline component sample. I'm half way to finish it. I decided to just detect whether a distinctive component is present, such as this in XPath:

    descendant::PT02000009/*[local-name()='LampiranIC']

    I planned to use this C# code snippet ( a part of the pipeline component modification):

    XPathNodeIterator nodeset = navigator.Select("descendant::PT02000009/*[local-name()='LampiranIC']");

                Console.WriteLine("nodeset.count = {0}", nodeset.Count);

                if (nodeset.Count > 0)
                {
                    Console.WriteLine("Element detected.");
                }
                else
                {
                    Console.WriteLine("Element __not__ detected.");
                }

     

    Later, the nodeset count could be used to return the detection result. The result will be used as parameter to set the namespace value in a configurable pipeline component parameter.

    Another function that I'm currently investigating is the XmlNode.SelectSingleNode(). If this function returns null, it means the element absent. This should be easy to use to replace the Select() function above.

     

    ========== edit (last status)=================

    I finally made a custom pipeline component which uses the XmlNode.SelectSingleNode() function to detect the type of incoming XML and set the namespace accordingly. It works :-). The custom pipeline component is based on the Microsoft BizTalk Adapters for Enterprise Applications Pipeline Component source code. A heavy modification on the base code was carried out to meet the spec. But, overall it works as expected.



    Monday, June 20, 2011 7:04 AM