views:

61

answers:

4
+1  Q: 

Xpath path help

I have the following XML:

<products>
    <product>       
        <name>Flat Panel Monitor</name>
        <code>LS123</code>
        <attributes>
            <attribute>
                <group>Color</group>
                <values>
                    <value>Red</value>
                    <value>Blue</value>
                    <value>Green</value>
                </values>
            </attribute>
            <attribute>
                <group>Warranty</group>
                <values>
                    <value>5 Year</value>
                </values>
            </attribute>
        </attributes>
    </product>
</products>

What Xpath would i use to get all value's with the attribute node with the group node value of "Color" ? A standard Xpath of /product/attributes/attribute/values/value would return all value's including value's from within the Warranty group but i need to keep them separate.

I guess in pseudocode what i'm saying is get all "value" where the parent node "values" is a sibling of the node "group" with the value "Color" - hopefully this is possible?

Thanks.

+4  A: 

You need to use square brackets to filter the nodes, thus: /product/attributes/attribute[group='Color']/values/value

Paul Butcher
By "square brackets" Paul meant a **predicate**.
Josh Davis
Thanks Josh, that's quite a valuable addition to the answer. I should have included the terminology so that he could look it up.
Paul Butcher
+2  A: 

You require only those value nodes that have a group 'uncle' of Color, so put that as a condition on the xpath you have already worked out:

/product/attributes/attribute/values/value[../../group = 'Color']

This says that for a value node to be valid, it must have a parent with a parent with a child with value Color.

AakashM
As proposed by Paul Butcher, it's more correct to apply a predicate on their common ancestor `<attribute/>`. It's also more performant, as the engine doesn't need to go deep into the tree then back up to the ancestor.
Josh Davis
@Josh, yes that is a better answer.
AakashM
A: 
//values[preceding-sibling::group[text()="Color"]]/value
Artefacto
A: 

Yet another option:

//value[ancestor::attribute[group='Color']]

DevNull