views:

31

answers:

2

I maybe be trying to do something invalid here, but maybe someone smarter than me knows the correct syntax to solve my problem. Given:


    <group code="vehicle">
        <line code="car">
            <cell>
                <box code="price">1000.00</box>
            </cell>
        </line>
        <line code="car">
            <cell code="sports">
                <box code="price">500.00</box>
            </cell>
        </line>
    </group>
If I use //*[@code="vehicle"]//*[@code="car"]//*[@code="price"], I will get both boxes returned (1000.00 and 500.00)--as expected but not what I want.

Is there an xpath syntax that will evaluate against all nodes that have an attribute of @code rather than skipping it if it doesn't match with the end result being that I only get back the first box (price of 1000.00)? Like asking, choose the first node with @code and that @code must equal "vehicle", then choose the next node with @code and that @code must equal "car", then choose the next node with @code and @code must equal "price".

A: 

Not an expert on xpath but XmlSpy seems to indicate that this would work?

(//*[@code="vehicle"]//*[@code="car"]//*[@code="price"])[1]
Dog Ears
Unfortunately this doesn't work for me. If the order of the `<line>` nodes are switched, then I'll get the wrong one. And I don't have control over their order in the original document.
Tres
so you down voted it?
Dog Ears
No, that wasn't me.
Tres
+1  A: 

Use:

   "//box
       [(@code='car' or @code='price' or @code='vehicle')
      and
       not(
             ancestor-or-self::*
                   [
                       @code
                      and
                       not(@code='car'
                              or
                               @code='price'
                              or
                               @code='vehicle'
                           )

                   ]
               )
       ]
Dimitre Novatchev
That didn't do it for me, but I see how my explanation led to your answer. Whereas the union operator does get all three matching nodes, which may have sounded like what I was asking for, I'm looking for just the deepest node `<box code="price">1000.00</box>` where every appearance of @code above it matches the xpath expression. I don't want the 2nd box to match because it has "sports" in the path, thereby invalidating it. The other way to think about it is: I want the box where *and only where* every @code matches the criteria.
Tres
@Tres: OK, I understood it now. See the updated solution. :)
Dimitre Novatchev
I pulled that over to try against a fragment of my original document and it looked very promising. I'll try it out in some more complicated scenarios and see if it holds for all my permutations. Thanks, Dimitre.
Tres