Fun With BizTalk, XPath, and Namespaces

The BizTalk Xpath statements usually required for my projects never seem to be as simple as the examples I find online. Usually, it’s because I’m stuck using namespaces, unlike virtually every sample Xpath ever written.

Last week I was working with an XML document where I wanted to capture the unique values in a repeating set. There are a few ways to do this, but I ended up going with the way Stephen Kaufman showed here:

<xsl:variable name=”unique-countries”
select=”//cities/city[not(@country=preceding-sibling::city/@country)]/@country” />

In the above example, you end up with a variable containing all the unique countries that correspond to the many cities in the list. My challenge was that I was going to use this variable within a map, using Inline XSLT as part of the Scripting functoid. And, my inbound document has elements from multiple namespaces. Using a namespace prefix was not going to work, so I had to write my elements in the
“//*[localname()=’node’ namespaceuri()=’namespace’]” way instead of the easier “//node” or (“//ns1:node”) way. Thank goodness for the Visual XPath tool which made testing my Xpath much easier.

You can’t just swap the node names in the above Xpath with the “[localname()=” namespaceuri()=”]” equivalent, as there are subtle differences. So given that my XML looked like this:


<Results>
 <QueryRecord>
  <DomainID></DomainID>
  <PageName></PageName>
</QueryRecord>
<QueryRecord>
  <DomainID></DomainID>
  <PageName></PageName>
 </QueryRecord>
</Results>

Let’s say I have two nodes I need to use in the Xpath statement:

My “converted” Xpath now looks like this:

<xsl:variable name=”unique-domains” select=”//*[local-name()=’QueryRecord’ and namespace-uri()=’http://namespace1′%5D[not(*[local-name()=’DOMAINID’ and namespace-uri()=’http://namespace1′%5D/text()=preceding-sibling::*[local-name()=’QueryRecord’ and namespace-uri()=’http://namespace1′%5D/*[local-name()=’DOMAINID’ and namespace-uri()=’http://namespace1′%5D/text())]/*[local-name()=’DOMAINID’ and namespace-uri()=’http://namespace1′%5D” />

Got that? Yowza. So I’m getting all the unique “domain ids” by grabbing each “domain id” where it doesn’t match a previous instance in the node tree. The main syntax difference between this Xpath and the one at the top is the “*” peppered around. If not included, you’ll get all sorts of does not evaluate to node set errors.

Any other “Xpath with namespaces in BizTalk” war stories or tips to share?

Technorati Tags:



Categories: BizTalk

5 replies

  1. Have you used XMLSpy to test your xpath?
    It worked for me and also with Biztalk.

  2. Are you aware of muenchian method? I don’t have problem with Biztalk Xpath at all. Sometimes I need to use ns0: in front of the node if Biztalk generate it that way.
    Usually this happens inside a multipart map. I generate the default map and then use it as a template to write xslt code.

    That is when ns0 or ns1 or ns2, etc.. come in.
    For other type of situation I used regular Xpath that is W3C standards and they all work.

    Can you tell me or even put a small project up somewhere about the pain you have with Biztalk Xpath and namespace.

  3. I’ve used to use XmlSpy all the time, but don’t have an active license anymore.

    I also have regularly used the muenchian method, but for some reason I can’t recall, I wanted to try a different way. But, now that I have it working this way, I may try and get alternative (read: higher performing) ways working as well.

  4. The xslt key structure in Muenchian method can do two things.
    1. Do the Muenchian method.
    2. Looking up predicate very fast using the key.
    so if you have some code like //Node1[attribute1=’something’]
    If the key is put on this Node1 and on attribute1, the concept works like an SQL indexed column look up WHERE = ‘something’.

    I have tested it, it is very fast , to look up some attribute over a 100,000 records took me 50 minutes, when I used the muenchian key to do the lookup(not the grouping, we are in use case #2), I cut this 50 minutes down to 5 minutes.

  5. I always use the /*[local-name()=’Node1′]/*[local-name()=’Node2′]/*[local-name()=’Node3′]

    I’ll avoid namespaces unless there is some ambiguity between the child nodes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: