XPath – the hidden language of BizTalk?#

For those of you who are unaware, XPath is a powerful query language for XML (ignoring XQuery for now).

In my experience I've worked with a lot of BizTalk developers who have come from a C# (and usually VB before that) background, and so haven't always had the background in XML, XSLT, XSD, and XPath needed to fully appreciate BizTalk.

Because let's face it: before you were working on BizTalk, how often did you need to deal directly with Xml? When writing ASP.NET web services, the .NET framework abstracts away the need to understand XML, leaving you with classes which are handily serialised/de-serialised across the wire for you.

Note: I have come across a similar pattern in the J2EE world – ask many Java developers about an Xml document they received as a request in a J2EE Web Service, and they'll only know about Beans, as the framework looks after the de-serialization from Xml into a Bean for them).

However, BizTalk is a different beastie: it works predominantly with data streams containing Xml.
Therefore the ability to know how to query this Xml without having to resort to C# code is very very important.

BizTalk 2004 and 2006/2006R2 support XPath 1.0 - as at this time, there is no support for XPath 2.0 in BizTalk.
You can get a good idea of the functions available in XPath 1.0 here (which is a useful summary of the W3 Recommendation)

(as a comparison, here's what XPath 2.0 gives you - here's hoping we get this in BizTalk sometime soon…!)

For a good primer on XPath, look here.

Every time you use a Distinguished Field in BizTalk, you're actually using XPath.
Every time you create a map… you're generating XSLT… which uses XPath.

Using XPath to select an element/attribute value from an Xml instance is very easy.
To see the XPath for the given element/attribute, open the Schema in the BizTalk Schema Editor, select the element/attribute you want to get a value for, and in the properties window select the value for Instance XPath:

This will give you an XPath statement something like:
/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()='']

In an orchestration, you can make use of XPath through the use of the xpath() function:

xpath(message, string)

The xpath() function can be used to both write and read information to/from a message (although to write information to a message, you need to call it from a Message Assignment shape, and the element/attribute you're setting the value of must already exist in the message).

Note that if you're reading information from a message, you have to cast the result back to an appropriate type, or use an XmlNode/XmlNodeSet variable.

For example, to get a string value you could use:
myXPath = "/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()='']/@*[local-name()='status' and namespace-uri()='']";
myValue = System.Convert.ToString(xpath(MyMessage, myXPath));

Note: if you tried the above on an XPath query which returned a node or node set, then instead of the element value in myValue, you'd get the text "System.Xml.XmlNodeSet" or similar…
This happens when your XPath selects an element, as opposed to the element's value (this doesn't apply to attributes).
In this case you have to modify your XPath to select the value of the element, instead of the actual element itself. You can do this by using the text() XPath function:
/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()='']/@*[local-name()='status' and namespace-uri()='']/text()

The beauty of XPath is that you can use it to operate across node-sets, and then filter (or query) the results through the use of predicates - similar to using a SQL query to select values from a database table.

For example, using a predicate of [1] will give you the first occurrence of something
/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''][1]
will give you the first Employee element

Correspondingly, [2] will give you the second, [3] the third, etc.

If you want to get a count of elements, you can use the count() function:
count(/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''])

And to use this in BizTalk:
myCount = System.Convert.ToInt32(xpath(MyMessage, "count(/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''])"))

I use this all the time when I call a web service, and get back a response which contains a collection of elements and I want to know how many I have.

You can even filter to find the number of elements which have a certain value.
For example, given the following XML:
<Employees xmlns:emp="urn:schema.mine.com:employees">
 <Employee id="1" status="Active">
 <Employee id="2" status="Active">
 <Employee id="2" status="Deceased">

I might want to get a count of Active employees:
count(/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()='']/@*[local-name()='status' and namespace-uri()=''][. = 'Active'])

Note: because status is an attribute and not an element, I used "." to reference the value of the attribute, rather than text() which I would use for an element.

In my time I've seen a lot of developers create a class representation of a message (using the xsd.exe tool), and de-serialise a message into this class just so that they could get a value e.g. a count – why take the hit of de-serialisation when you can just pull the value out of the message directly?

One of the tricky things about writing XPath queries is that it's difficult to test them – you need a tool like Altova XmlSpy or Stylus Studio which can test an XPath statement on an instance of an Xml document.
There's no built-in support in Visual Studio for testing XPath queries.

Which is why I wrote DanSharp XmlViewer.

This tool lets you get the XPath to select a given element/attribute from an Xml instance document but more importantly acts as an XPath scratchpad so you can test your XPath queries:

It even shows you when your syntax is incorrect (as in the above, highlighted red – you can hover over the text to see the error).

I use this tool all the time to write XPath queries as I can test them before putting them into BizTalk.

Get the tool here.

Friday, November 30, 2007 4:53:03 PM (GMT Standard Time, UTC+00:00) #    Comments [0]  |  Trackback Tracked by:
"http://blastpr.com/wiki/js/pages/tramadol/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://blastpr.com/wiki/js/pages/coumadin/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://blastpr.com/wiki/js/pages/effexor/index.html" (http://blastpr.com/wiki/j... [Pingback]
"http://blastpr.com/wiki/js/pages/cymbalta/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://morningside.edu/mics/_notes/pages/nexium/index.html" (http://morningside... [Pingback]
"http://morningside.edu/mics/_notes/pages/clomid/index.html" (http://morningside... [Pingback]
"http://morningside.edu/mics/_notes/pages/effexor/index.html" (http://morningsid... [Pingback]
"http://morningside.edu/mics/_notes/pages/prilosec/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/synthroid/index.html" (http://mornings... [Pingback]
"http://morningside.edu/mics/_notes/pages/cymbalta/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/paxil/index.html" (http://morningside.... [Pingback]
"http://morningside.edu/mics/_notes/pages/celexa/index.html" (http://morningside... [Pingback]
"http://morningside.edu/mics/_notes/pages/ultram/index.html" (http://morningside... [Pingback]
"http://blastpr.com/wiki/js/pages/claritin/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://morningside.edu/mics/_notes/pages/celebrex/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/claritin/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/accutane/index.html" (http://morningsi... [Pingback]
"http://blastpr.com/wiki/js/pages/ultram/index.html" (http://blastpr.com/wiki/js... [Pingback]
"http://blastpr.com/wiki/js/pages/synthroid/index.html" (http://blastpr.com/wiki... [Pingback]
"http://morningside.edu/mics/_notes/pages/lipitor/index.html" (http://morningsid... [Pingback]
"http://blastpr.com/wiki/js/pages/wellbutrin/index.html" (http://blastpr.com/wik... [Pingback]
"http://blastpr.com/wiki/js/pages/melatonin/index.html" (http://blastpr.com/wiki... [Pingback]
"http://blastpr.com/wiki/js/pages/prozac/index.html" (http://blastpr.com/wiki/js... [Pingback]
"http://blastpr.com/wiki/js/pages/prilosec/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://blastpr.com/wiki/js/pages/lipitor/index.html" (http://blastpr.com/wiki/j... [Pingback]
"http://morningside.edu/mics/_notes/pages/viagra/index.html" (http://morningside... [Pingback]
"http://bot.moldseo.info/ping/blogs.php?pg=62552" (http://bot.moldseo.info/ping/... [Pingback]
"http://bot.moldseo.info/ping/blogs.php?pg=96314" (http://bot.moldseo.info/ping/... [Pingback]
"http://bot.moldseo.info/ping/blogs.php?pg=159958" (http://bot.moldseo.info/ping... [Pingback]


Comments are closed.
All content © 2020, Daniel Probert
On this page
This site
<September 2020>
Blogroll OPML

Powered by: newtelligence dasBlog 2.3.12105.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts

Pick a theme: