0
votes

For reasons out of scope for this question I need to be able to handle multiple xml documents of the same structure but belonging to different namespaces (don't ask).

To achieve this I've become very accustomed to using an xpath like the following for many of my value selections:

//*[local-name()='apple']/*[local-name()='flavor']/text()"

My lack of understanding of predicates is preventing me from selecting a node's value based upon a sibling node's value. Consider the following xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<fruit>
    <apple>
        <kind>Red Delicious</kind>
        <flavor>starchy</flavor>
    </apple>
    <apple>
        <kind>Granny Smith</kind>
        <flavor>tart</flavor>
    </apple>
    <apple>
        <kind>Pink Lady</kind>
        <flavor>sweet</flavor>
    </apple>
</fruit>

Let's say I want to write an xpath that will select the flavor of a Granny Smith apple. While I would normally do something like:

//apple[kind/text()='Granny Smith']/flavor/text()

I cannot figure out how to merge the concept of utilizing local-name() to be namespace agnostic while still selecting a node based upon a sibling's value.

In short, what is the xpath necessary to return "tart" regardless of what namespace the input fruit xml document belongs to?

1
I'm not completely sure I understand, but //*[contains(.,'tart')] is what I think you're looking for. To be more specific, though: //apple[contains(@flavor, 'tart')] would return the apple in question, assuming that there are other fruits that might also have a child of tagname flavor. - Bill Hileman
I want the equivalent of this xpath that will be namespace ignorant and work for any fruit xml regardless of which namespace it belongs (as long as the structure is above): //apple[kind/text()='Granny Smith']/flavor/text() let's assume we don't know what the flavor is for sake of argument - Russ
I think I understand now. I can tell you how I'd accomplish this in Java if it helps: "//*[local-name()='type']/*[local-name()='property']/../name()='output']/text()".replace("type","apple").replace("property","kind").replace("output","flavor"); (air-code, untested) - Bill Hileman
//*[local-name()="apple" and *[local-name()="kind" and text()="Granny Smith"]]/*[local-name()="flavor"]/text() - splash58

1 Answers

0
votes

I need to be able to handle multiple xml documents of the same structure but belonging to different namespaces (don't ask)

My preferred way to handle this is to first transform the data to use a single namespace, and then do the transformation proper. Doing it this way (a) keeps the real transformation much simpler, (b) puts all the namespace conversion logic in one place, and (c) makes the namespace conversion logic reusable - you can use the same transformation regardless how the data will subsequently be used.