user1200340
user1200340

Reputation: 167

XPath to select unique list of elements that have a certain attribute with Xpath 2.0

I'm having a bit of trouble getting a unique list of elements (based on name) that also have a certain attribute. I can get a list of either of those, but the combined list is what's tripping me up. My xml looks like this:

<global>
    <discipline name="tracks">
        <group name="Normal"/>
        <group name="Gloss" PackGroup="Diffuse"/>
        <group name="Mask"/>
        <group name="Diffuse"/>
        <group name="Tint" PackGroup="Gloss"/>
    </discipline>
    <discipline name="trains">
        <group name="Mask"/>
        <group name="Diffuse" PackGroup="Mask"/>
    </discipline>
</global>

i can get a distinct list of group elements easily enough using this xpath query:

/configuration/global/discipline/group[not(@name = following::group/@name)]

and getting the list of group elements that have PackGroup attribute defined is trivial as well:

/configuration/global/discipline/group[@PackGroup]

however, i can't seem to get a unique list of elements that have PackGroup attribute defined. i've tried this:

/configuration/global/discipline/group[not(@name = following::group/@name) and @PackGroup]
/configuration/global/discipline/group[not(@name = following::group/@name) and contains(@PackGroup, '*')]

which return no elements and

/configuration/global/discipline/group[not(@name = following::group/@name) and contains(@PackGroup, '')]

which returns just the unique list. Does anyone know what the correct xpath query is to get what i'm looking for?

(i'm working in C# and xpath 2.0 in case that matters)

thanks!

Upvotes: 2

Views: 11562

Answers (2)

Michael Kay
Michael Kay

Reputation: 163342

A more efficient solution (O(n log n) rather than O(n*n)) would be

for $n in distinct-values(//group[@Packgroup]/@name) 
return (//group[@Packgroup][@name=$n])[1]

Upvotes: 6

LarsH
LarsH

Reputation: 27994

I think what you're looking for is

/configuration/global/discipline/group
  [not(@name = following::group[@Packgroup]/@name) and @PackGroup]

You want to make sure that both the group you're filtering (the first group in the expression) and the following group that you're checking for (the second group) have a @Packgroup attribute.

There may also be a way to do this using the distinct-values() function, but I haven't thought how at this point.

Upvotes: 2

Related Questions