Introduction

XPath can provide a valuable and efficient way to retrieve values from BizTalk messages, especially when you can't use distinguished fields, for example in looping records. However, it can be quite a complicated task as well, to find out how to retrieve a certain value. To that end, this post contains a list of XPath filter expressions commonly used in BizTalk Server. Unless specified differently, these will all return a node set, which can be loaded into an XML element. In all the sample statement we will use the XML below.

<Order>
    <Delivery>
        <DeliveryType>Home</DeliveryType>
        <BoxInfo>
            <BoxID>22</BoxID>
        </BoxInfo>
    </Delivery>
    <Delivery>
        <DeliveryType>Work</DeliveryType>
        <BoxInfo>
            <BoxID>35</BoxID>
        </BoxInfo>
    </Delivery>
    <Delivery>
        <DeliveryType>Home</DeliveryType>
        <BoxInfo>
            <BoxID>12</BoxID>
            <BoxID>87</BoxID>
        </BoxInfo>
    </Delivery>
    <Boxes>
        <Box material="cardboard">
            <ID>12</ID>
            <Contents>Envelopes</Contents>
        </Box>
        <Box material="cardboard">
            <ID>22</ID>
            <Contents>Surface Pro 2</Contents>
        </Box>
        <Box material="plastic">
            <ID>35</ID>
            <Contents>Stickers</Contents>
        </Box>
        <Box material="cardboard">
            <ID>87</ID>
            <Contents>Stamps</Contents>
        </Box>
    </Boxes>
</Order>

Filter on index

The first option is to filter using indexes. Beware XPath indexing starts at 1, unlike C# indexes.

Samples

Get the second delivery node.

/*[local-name()='Order']/*[local-name()='Delivery'][2]

Get the deliverytype node of the second delivery.

/*[local-name()='Order']/*[local-name()='Delivery'][2]/*[local-name()='DeliveryType']

Filter on subnode text

You can also use filters on the texts of the nodes. This will return all nodes where the expressed filter is met.

Samples

Get all delivery nodes, which have a deliverytype of Home.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='DeliveryType'][text()='Home']]

Get the deliverytype node of the delivery for boxid 87.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='BoxInfo']/*[local-name()='BoxID'][text()='87']]/*[local-name()='DeliveryType']









Get the deliverytype node, of the boxes which contains the stickers.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='BoxInfo']/*[local-name()='BoxID'][text()=/*[local-name()='Order']/*[local-name()='Boxes']/*[local-name()='Box'][*[local-name()='Contents'][text()='Stickers']]/*[local-name()='ID']]]/*[local-name()='DeliveryType']

Combined filtering

You can also combine various filters in a single expression, making this a very powerful way of getting specific nodes.

Samples

Get the second delivery, where deliverytype is home.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='DeliveryType'][text()='Home']][2]

Get the delivery, where deliverytype is work, and boxid is 35.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='BoxInfo']/*[local-name()='BoxID'][text()='35']
and *[local-name()='DeliveryType'][text()='Work']]

Logical operators

As seen in the previous sample, you can also use logical operators like and and or to make your filters more fine-grained.

Samples

Get the deliveries, which contain boxid 12 or boxid 22.

/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='BoxInfo']/*[local-name()='BoxID'][text()='12'
or text()='22']]

Get node value

In the above examples, you are getting the actual node. Often though, you will want to get the value of a node. This can be done by placing the string or number expression around your XPath.

Samples

Get the value of the contents of the first box as a string.      

string(/*[local-name()='Order']/*[local-name()='Boxes']/*[local-name()='Box'][1]/*[local-name()='Contents'])

Get the value of the ID of the second box as a number.      

number(/*[local-name()='Order']/*[local-name()='Boxes']/*[local-name()='Box'][2]/*[local-name()='ID'])

Get count of node

Often you will want to count how often a certain node occurs in your message. To do this using XPath, place the count expression around your XPath.

Samples

Count how many deliveries there are.

count(/*[local-name()='Order']/*[local-name()='Delivery'])

Count, how many deliveries with deliverytype home there are.

count(/*[local-name()='Order']/*[local-name()='Delivery'][*[local-name()='DeliveryType'][text()='Home']])

Get distinct values

Sometimes you will want to get the unique (distinct) values of a certain repeating node. This can also be done easily using XPath both for nodes and attributes.

Samples

Get the distinct deliverytypes (in this case Work and Home), note that after preceding-sibling:: we first set the sibling node name, and then the name of the node for which we want to get the values.

/*[local-name()='Order']/*[local-name()='Delivery'][not(*[local-name()='DeliveryType']/text()=preceding-sibling::*[local-name()='Delivery']/*[local-name()='DeliveryType']/text())]/*[local-name()='DeliveryType']

Get the distinct values for the box materials (cardboard and plastic), note that in this case we do not specify the sibling node name after preceding-sibling::, instead we immediately access the attribute.

/*[local-name()='Order']/*[local-name()='Boxes']/*[local-name()='Box'][not(@material=preceding-sibling::*/@material)]/@material

Tools

To avoid having to deploy your projects each time you want to test a change in your XPath, use one of the following tools. These tools especially help out when setting up more complex XPath expressions.

See Also

Another important place to find an extensive amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.