Charles Young

  Home  |   Contact  |   Syndication    |   Login
  144 Posts | 55 Stories | 362 Comments | 376 Trackbacks

News

MVP - Microsoft Most Valuable Professional

Twitter












Article Categories

Archives

Post Categories

Image Galleries

Alternative Feeds

BizTalk Bloggers

BizTalk Sites

CEP Bloggers

CMS Bloggers

Fun

Other Bloggers

Rules Bloggers

SharePoint Bloggers

Utilities

WF Bloggers

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

Feedback

# re: BizTalk Server 2006: An xpath() Function problem 12/28/2006 8:00 PM Leonid Ganeline
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?

# re: BizTalk Server 2006: An xpath() Function problem 12/29/2006 6:56 PM Charles Young
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.

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

# re: BizTalk Server 2006: An xpath() Function problem 1/23/2007 8:47 AM Charles Young
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.

# re: BizTalk Server 2006: An xpath() Function problem 9/20/2007 6:21 PM PaulE
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.

# re: BizTalk Server 2006: An xpath() Function problem 11/28/2007 9:10 PM Zoe Hart
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.

# re: BizTalk Server 2006: An xpath() Function problem 11/30/2007 1:46 PM Zoe Hart
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.

# re: BizTalk Server 2006: An xpath() Function problem 11/30/2007 1:49 PM Charles Young
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 :-)

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

# re: BizTalk Server 2006: An xpath() Function problem 3/7/2008 8:53 AM Sftco Insurance
Thats cool post, xpath words fine now.

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

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: