Advanced XPath filter strategies inside Orchestrations

|  Posted: August 12, 2021  |  Categories: BizTalk Server

In my previous post – How to count XML Nodes Inside Orchestrations – I explained how to use the XPath count() function inside Orchestrations to count the number of nodes present on an XML message. In some cases, you need to count them based on some basic filter conditions. Often we want these capabilities to … Continue reading Advanced XPath filter strategies inside Orchestrations

In my previous post – How to count XML Nodes Inside Orchestrations – I explained how to use the XPath count() function inside Orchestrations to count the number of nodes present on an XML message. In some cases, you need to count them based on some basic filter conditions.

Often we want these capabilities to implement some business logic inside your Orchestrations, like:

  • if records exist then, map them and send them to a specific system
  • otherwise, terminate the business flow logic

In this blog post, we will be using once again the XPath count() function to explain how to specify advanced filters conditions/expressions inside orchestrations. We can use this approach to count the elements present in an XML message, but also to retrieve them if that is required. For that, we may need a slight adjustment of the XPath query.

Once again, to count the number of nodes present in a message you need to use the following template expression:

<variable_name> = System.Convert.ToInt32(xpath(<message_name>,”count(<xpath_query>)”)); 

Despite the template expression be the same, you will find several approaches to count the nodes. 

Count/Filter all nodes, based on a single filter condition

In this first example, we want to count or retrieve all the nodes or elements based on a single filter condition. In this case, we count how many nodes exist where Type == ‘P’.

varCountSF = System.Convert.ToInt32(xpath(msgInput,”count(//[local-name()=’XMLSample’]/[local-name()=’Object’]/*[local-name()=’Type’][text()=’P’])”));

Of course, if I would like, for example, to retrieve the value of the first Type element based on that condition, I would use:

<variable_name> = xpath(<message_name>,”string(//*[local-name()=’XMLSample’]/*[local-name()=’Object’][1]/*[local-name()=’Type’][text()=’P’])”); 

The result will be ‘P’.

Now, if I want to retrieve the first Name element where Type is ‘P’, then the XPath query will be slightly different:

<variable_name> = xpath(<message_name>,”string(//*[local-name()=’XMLSample’]/*[local-name()=’Object’][*[local-name()=’Type’][text()=’P’]][1]/*[local-name()=’Name’])”);

In this query, the result will be ‘Sandro’ (if you see the sample XML message present in the source code).

Count/Filter all nodes, based on a single filter condition with Logical operators:

Now let’s complicate a little more. Here, I want to count all the nodes or elements based on a single filter but using a Logical Operator. For example, count how many nodes exist where Type == ‘P’ OR Type == ‘A’.

varCountOr = System.Convert.ToInt32(xpath(msgInput,”count(//[local-name()=’XMLSample’]/[local-name()=’Object’]/*[local-name()=’Type’][text()=’P’ or text()=’A’])”));

Still quite simple.

Count/Filter all nodes, based on multiple filter conditions:

Now, let’s try using multiple filter conditions inside one XPath query. For example, I want to count how many nodes exist where Type == ‘P’ and Name == ‘Sandro’.

varCountMF = System.Convert.ToInt32(xpath(msgInput,”count(//[local-name()=’XMLSample’]/[local-name()=’Object’][[local-name()=’Type’][text()=’P’]][[local-name()=’Name’][text()=’Sandro’]])”));

Count/Filter all nodes, with unique (distinct) values

The last, and probably the most complex, is to count or retrieve distinct nodes or elements, this is a different filter condition. For example, I want to count how many distinct (unique) Name nodes exists on the message. For that, we need to use the preceding-sibling axis. 

varCountDistinct = System.Convert.ToInt32(xpath(msgInput,”count(//[local-name()=’XMLSample’]/[local-name()=’Object’][not([local-name()=’Name’]/text()=preceding-sibling::[local-name()=’Object’]/[local-name()=’Name’]/text())]/[local-name()=’Name’])”));

Of course, the same principles explained here can be used for attributes as well.

Download

You can access and download this sample code from GitHub here: POC: BizTalk – Advanced Filter With XPath Inside Orchestrations

Author: sandro

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community.

Leave a Reply

Your email address will not be published. Required fields are marked *