Geeks With Blogs

News
Charles Young

I spent a couple of hours today looking at the problem we encountered yesterday with the xpath() function in BizTalk.    We were attempting to use an XPath to extract the value of a nested element and assign it to a string variable.   The nested element (<Direction>) was in the global (anonymous) namespace, but was a child of an element in a named namespace.   The code failed on XmlSerializer de-serialisation with an error saying "<Direction xmlns=''> not expected".

At first, I strongly suspected that the problem was due to the use of the anonymous namespace, especially as the element was defined in a schema that was then imported into the message schema.   Both schemas had the 'Element FormDefault' attribute set to default (unqualified), and we had ended up with a horrible interleaved mess of elements, some of which were in defined namespaces, whilst others were in the global namespace.   Always, always set Element FormDefault to 'Qualified' in your schemas, unless you have a really good reason not to.   We are now in the process of changing all our schemas to eliminate the use of global namespaces.

After a while, I convinced myself that there was a problem with the .NET XmlSerializer, especially after reading a number of news group threads on the Internet.   From what I read, it seemed that the XmlSerializer might have problems with "xmlns=''" declarations. To prove the point, I wrote a little code to reproduce the issue.   Unfortunately, however, the XmlSerializer worked perfectly, whatever I did.  It seems that it has no issues at all with "xmlns=''".

I then spent some time with Reflector, digging into the BizTalk code to see what it was doing, and eventually I discovered the problem...and it was all our fault!!

We had a line of code in the orchestration that attempted to use the BizTalk xpath() function to return the value held in the <Direction> element and assign it to a string variable.    The only problem was that the XPath was addressing the <Direction> node, and not its contents.   The XPath processor uses XML DOM internally, and expressions return XML nodes or node sets.   In our case, the XPath we used was returning an XmlElement node from our XML message.   We were trying to assign this to a string variable (doh)!

This very basic XPath error was made opaque by the fact that we got no compile-time error, but instead suffered an run-time exception thrown by the XmlSerializer class.   You might reasonably expect that the exception would indicate some kind of type mismatch or cast failure.    Instead, we got a general-purpose XmlSerializer exception statibg that the XML content was unexpected.   The reason for this becomes clear when we looked a little deeper into what is happening when we call the xpath function.   BizTalk generates C# code for the line that calls the xpath function.   The generated code calls a method to which it passes the Type of the variable to which the result of the method will be assigned.   This Type is used to initialise an instance of XmlSerializer used internally by BizTalk.   In our case, we ended up with an instance of XmlSerializer that attempted to de-serialise an XmlElement (addressed by the XPath) as a string object.   This, of course, didn't work, and the XmlSerializer returned an exception saying that the XmlElement 'was not expected'.

The XmlSerializer object is used to deserialise XML content obtained using XPathNavigator and XmlNodeReader.   In a reversal of the principle of strong typing, BizTalk's XLang/s langauge effectively 'trusts' the developer to select the right type of variable to hold the results of the xpath() function.   If the developer gets this wrong (as we did), the code blindly attempts to perform de-serialisation to the incorrect type, and fails at run time.

The best fix in our case was simply to extend the end of the XPath with '/text()'.   This returns the text node contained in the <Direction> node (XML DOM sees the text node as a nested node).   This nicely de-serialises to a string.    Another option would be to retain the XPath as is, but assign the result to an XmlElement variable, and then extract the inner text.   This is less direct, and may require an additional atomic scope because XmlElement is not serialisable.

So, the problem was nothing to do with the use of anonymous namespaces or the .NET XmlSerializer.   It was a basic logical error in our own code that took ages to spot due to the exception that was raised.   If you use the xpath function and get an "<xxxxx xmlns=''> not expected" exception, check your XPath to see what it is actually returning, and the variable you are assigning the results to.

Posted on Tuesday, December 12, 2006 11:19 PM BizTalk Server 2004/2006 | Back to top


Comments on this post: BizTalk Server 2006: An xpath() Function problem

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Charles,
If it was not the Unqualified elements were the causethen why we should always use "Qualified"? Using Xpath in the BizTalk artifacts is the only cause? or there are others?
Left by Leonid Ganeline on Dec 28, 2006 8:00 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Oh, this is offered as a simple 'rule' to help avoid creating exactly the kind of namespace confusion we had with the original versions of the schemas. By setting the element form default to 'Qualified', you force elements which are declared locally in a schema to always be namespace-qualified (by 'locally', I mean as part of a complex type rather than at the global level in the XSD). If you don't use this setting, then you run a big risk of inadvertently defining schemas for XML where the document ('root') element is in the target namespace but nested elements are not namespace qualified. If you combine this with imported schemas, you can easily end up with an even greater mess in which non-qualified elements are interleaved with qualified elements from a variety of different namespaces. Of course, you might sometimes want to define your XSD in this fashion, but generally you do not want to. Setting the Element Form default attribute to 'Qualified' is a simple discipline which generally helps those who are not XSD gurus from accidently ending up in namespace hell.
Left by Charles Young on Dec 29, 2006 6:56 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Hi Charles,
We need you back on the track........
Left by Saravanan on Jan 23, 2007 1:27 AM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Thanks. I haven't gone away, honest! I'm currently working on a whitepaper or two, which kinda gets in the way of writing blog articles. I do hope and plan to blog more extensively about BTS R2 RFID services as time goes on.
Left by Charles Young on Jan 23, 2007 8:47 AM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Thanks, Charles! I was experiencing exactly the same problem. Your insight and solution to the problem is greatly appreciated! Love the detailed explanation and research.

In addition to adding "/text()" to the xpath, in my case I also had to put the entire xpath expression in a string() method. So, my full expression looked like "string(.../text())". It ran without error with the string(), but I always got an empty string back instead of the text value which was in my selected node.
Left by PaulE on Sep 20, 2007 6:21 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
I am getting the error you describe but not under the same conditions. My source message contains 1 to n <detail-line> elements, each of which contains a set of child elements. I've verified that my xpath expression correctly extracts a single <detail-line> element (and all its child elements). I am trying to assign that element to a BizTalk message variable. Shouldn't that assignment work. I'm getting the "<detail-line xmlns='http://www.tunghead.com/GCOOMSmessages'> was not expected" error. That is the correct root node for the message schema. Why would it be unexpected?

Thanks.
Left by Zoe Hart on Nov 28, 2007 9:10 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Please ignore my previous comment. I removed a lot of debug code (which may itself have been introducing an error) and found that the code I thought was failing actually works.
Left by Zoe Hart on Nov 30, 2007 1:46 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Thanks Zoe. I did have a brief attempt to reproduce the problem, but couldn't. So I won't spend any time on this over the weekend :-)
Left by Charles Young on Nov 30, 2007 1:49 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Very good information. The the xpath() function can give you problems sometimes,but it all works out in the end.
Left by Atlanta Georgia Real Estate on Feb 10, 2008 3:54 AM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Thats cool post, xpath words fine now.
Left by Sftco Insurance on Mar 07, 2008 8:53 AM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
It was a great help. I had the same issue. But then string( ) had to be used.
Left by Clement Baker on Aug 14, 2008 8:50 PM

# re: BizTalk Server 2006: An xpath() Function problem
Requesting Gravatar...
Hi Charles.

Whenever I have the time, I read your blog. The challenge is, that you spend a great deal of time describing your issues in details, which takes time to read :) The benefit is the exact same thing, naturally - that you don't just deliver a solution, but also the rarely seen explanation of WHY it fails.

Keep it up, Charles!
Left by Jan Eliasen on Jun 27, 2010 8:57 AM

Your comment:
 (will show your gravatar)


Copyright © Charles Young | Powered by: GeeksWithBlogs.net