Using BizTalk xpath() Function to Retrieve Optional Nodes

I often suffer a bit of trepidation when trying to retrieve values for optional XML nodes using the built-in xpath() function in an orchestration, as I wonder if it will result in an exception of some kind if the node isn’t found in the message.  This concern is heightened by reading Microsoft’s own documentation of the xpath function on MSDN:

The engine is not schema-aware, so you can only read values from or write values to a node that exists in the containing message (the complete path must exist), or the engine will raise an exception. This is true even if you supply a default value.

The conclusion from this is that if the node doesn’t exist in the message instance, you’ll get a runtime error trying to read from it using xpath(), right?

Wrong! In fact, as Leonid Ganeline proved in an older blog post, you will either get an empty string or “null”, depending on whether you wrap the XPATH expression in a string() function or not:

      • xpath(myMessage, “//*[local-name()=’nonExistentNode’]/text()“)    –>    null
      • xpath(myMessage, “string(//*[local-name()=’nonExistentNode’])“)   –>    String.Empty

Note the use of the text() function in the first option. Failure to use this would cause an InvalidOperationException if the node were actually present, because you are trying to assign an XmlNode to a string. Another option to using the text() function would be to wrap the result in System.Convert.ToString(); however, this will return an empty string instead of null if the node isn’t present.

If your types are not strings, then you would probably use a boolean() or a number() function instead of string(). However, be prepared for Invalid Format errors if the type conversion fails!

For most cases, the safest option would probably be to always wrap the result in System.Convert.ToString(), like so:

strValue = System.Convert.ToString(
xpath(myMessage, “//*[local-name()=’myOptionalField’]”));

By assigning this to a string, you can then avoid most invalid format errors and test the result yourself. You can also optionally choose to use the string() function inside the xpath() function, regardless of the actual datatype, as this will convert invalid boolean or number types to an empty string:

strValue = System.Convert.ToString( xpath(myMessage,
string(//*[local-name()=’myOptionalField’])“));

The table below shows the results of different scenarios using this approach. In all cases, the result of the xpath() function was wrapped inside a System.Convert.ToString() method and assigned to a string variable:

Schema Node Data Type XPath expression wrapped? Instance Node State
Present with value Empty node Null (xs:nil = true) No node (missing)
xs:string No *see below “” “” “”
string() value “” “” “”
xs:int No *see below “” “” “”
number() value NaN NaN NaN
string() value “” “” “”
xs:boolean No *see below “” “” “”
boolean() **True True True False
string() value “” “” “”

*returned “Microsoft.XLANGs.Core.Part+ArrayBasedXmlNodeList”

**Always returned “True”, no matter what value was entered (-1, 0, 1, true, false, blah, etc.)

For those that are interested, here is the code in my expression shape that I tested with:

strValue = System.Convert.ToString(xpath(Message_1, “//*[local-name()=’OptionalField1′]”));
System.Diagnostics.Trace.WriteLine(“INFO: Value: ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

strValue = System.Convert.ToString(xpath(Message_1, “string(//*[local-name()=’OptionalField1′])”));
System.Diagnostics.Trace.WriteLine(“INFO: Value (using string()): ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

System.Diagnostics.Trace.WriteLine(“INFO: ——————————————————–“);
strValue = System.Convert.ToString(xpath(Message_1, “//*[local-name()=’OptionalIntField1′]”));
System.Diagnostics.Trace.WriteLine(“INFO: Value: ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

strValue = System.Convert.ToString(xpath(Message_1, “number(//*[local-name()=’OptionalIntField1′])”));
System.Diagnostics.Trace.WriteLine(“INFO: Value (using number()): ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

strValue = System.Convert.ToString(xpath(Message_1, “string(//*[local-name()=’OptionalIntField1′])”));
System.Diagnostics.Trace.WriteLine(“INFO: Value (using string()): ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

System.Diagnostics.Trace.WriteLine(“INFO: ——————————————————–“);
strValue = System.Convert.ToString(xpath(Message_1, “//*[local-name()=’OptionalBoolField1′]”));
System.Diagnostics.Trace.WriteLine(“INFO: Value: ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:  [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

strValue = System.Convert.ToString(xpath(Message_1, “boolean(//*[local-name()=’OptionalBoolField1′])”));
System.Diagnostics.Trace.WriteLine(“INFO: Value (using boolean()): ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:  [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

strValue = System.Convert.ToString(xpath(Message_1, “string(//*[local-name()=’OptionalBoolField1′])”));
System.Diagnostics.Trace.WriteLine(“INFO: Value (using string()): ” + strValue);

if(strValue == null){ System.Diagnostics.Trace.WriteLine(“INFO:  [Value was null]”); }
if(strValue == System.String.Empty){ System.Diagnostics.Trace.WriteLine(“INFO:   [Value was empty string]”); }

System.Diagnostics.Trace.WriteLine(“INFO: ========================================================”);

For more information and resources about the BizTalk xpath() function, see the BizTalk Orchestrations XPath Survival Guide on TechNet.

I hope this helps instil some confidence in using the xpath() function in your orchestrations, as it is often the simplest and most powerful way to access message content, particularly for repeating nodes where distinguished fields are not allowed.

About Dan Toomey
Enterprise integration geek, Microsoft Azure MVP, Pluralsight author, public speaker, MCSE, MCT, MCTS & former professional musician.

One Response to Using BizTalk xpath() Function to Retrieve Optional Nodes

  1. Pingback: BizTalk – Decide on XPath xs:boolean | My Blog.

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 )

Facebook photo

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

Connecting to %s

John Glisson - Geek of the Cloth

Thoughts on integration, technology and what-not...

Prashant BizTalk And Azure Integration Blogs

My Integration Experiences - BizTalk And Azure Integration

The CRUCIBLE

THINK: It's not illegal....yet.....

Abdul Rafay's BizTalk Blog

My experiences with BizTalk related to architecture, development and performance in my enterprise.

BizTalk musings

Issues, patterns and useful tips for BizTalk development

EAI Guy.net

Enterprise Applicaiton Integration and SOA 2.0

Connected Pawns

Mainly BizTalk & Little Chess

Adventures inside the Message Box

BizTalk, Azure, and other tools in the Microsoft stack - Johann Cooper

Biz(Talk)2

Talk, talk and more talk about BizTalk

Richard Seroter's Architecture Musings

Blog Featuring Code, Thoughts, and Experiences with Software and Services

Sandro Pereira BizTalk Blog

My notes about BizTalk Server 2004, 2006, 2006 R2, 2009, 2010, 2013 and now also Windows Azure BizTalk Services.

BizTalk Events

Calendar of BizTalk events all over the world!

Mind Over Messaging

Musings on BizTalk, Azure, and Enterprise Integration

WordPress.com News

The latest news on WordPress.com and the WordPress community.

%d bloggers like this: