XPath Predicate Issue

139 Views Asked by At

I've got an XPath expression with a predicate that selects a person's name and ID from within a nested element, using the XPathNavigator.Select method.

This works:

root/all_clients/client/client_name_and_ID[client_ID = 'xxx']

This also works:

root/all_clients/client[client_name_and_ID/client_ID = 'xxx']/client_name_and_ID

When I take the predicate to the next level, it does not work:

root/all_clients[client/client_name_and_ID/client_ID = 'xxx']/client/client_name_and_ID

I do not get any filtering, but the entire set.

Is this due to a limitation inherent within XPath, within ASP.NET, or am I doing something stupid?

What follows is a snippet from the relevant XML file:

<?xml version="1.0" encoding="utf-8"?>

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="file:///n:\Projects\XML\Medical\Example_01.xsd">

<all_clients>

    <client>
        <client_name_and_ID>
            <first_name>Fred</first_name>
            <middle_name>James</middle_name>
            <last_name>Bowman</last_name>
            <client_ID>1</client_ID>
        </client_name_and_ID>
    </client>

    <client>
        <client_name_and_ID>
            <first_name>Mark</first_name>
            <middle_name>David</middle_name>
            <last_name>Colder</last_name>
            <client_ID>2</client_ID>
        </client_name_and_ID>
    </client>

    <client>
        <client_name_and_ID>
            <first_name>Joe</first_name>
            <last_name>Lewis</last_name>
            <client_ID>3</client_ID>
        </client_name_and_ID>
    </client>

    <client>
        <client_name_and_ID>
            <first_name>Sam</first_name>
            <last_name>Plank</last_name>
            <client_ID>4</client_ID>
        </client_name_and_ID>
    </client>
</all_clients>

</root>
2

There are 2 best solutions below

1
On BEST ANSWER

The last query is matching an all_clients element that contains any matching client underneath it. It then selects clients under this all_clients without the filter applied, so it selects all of the client elements.

You should save the filter for the end of the XPath. First select down to the type of element you want, and then apply a filter to those elements. Try these XPaths:

<!-- Select client_ID element. -->
root/all_clients/client/client_name_and_ID/client_ID[. = 'xxx']

<!-- Select client_name_and_ID element. -->
root/all_clients/client/client_name_and_ID[client_ID = 'xxx']

<!-- Select client element. -->
root/all_clients/client[client_name_and_ID/client_ID = 'xxx']
1
On

That's normal. All client nodes are children of the all_clients node. Therefore it will always qualify to the condition "all elements named all_clients having at least one match of a descendant client/client_name_and_ID/client_ID = 'xxx'" which is what you have coded.