Search code examples
debuggingxpathsubquerypredicatexpath-1.0

xpath expression to simulate subquery with multiple creiteria


I have to find a value in an xml using two criteria on two differents nodest using xpath 1.0

I'try to explain with an example: If we have the following xml

<root>
<obj>
    <index>5</index>
    <datalist>
        <data>
            <code>X</code>
            <value>AAA</value>
        </data>
        <data>
            <code>Y</code>
            <value>BBB</value>
        </data>
    </datalist>
</obj>
<obj>
    <index>3</index>
    <datalist>
        <data>
            <code>Z</code>
            <value>CCC</value>
        </data>
    </datalist>
</obj>
<obj>
    <index>4</index>
    <datalist>
        <data>
            <code>X</code>
            <value>DDD</value>
        </data>
    </datalist>
</obj>
<obj>
    <index>2</index>
    <datalist>
        <data>
            <code>Y</code>
            <value>EEE</value>
        </data>
    </datalist>
</obj>

we would like to retrive the <value> of the <obj/data> with <code=X> within the <obj> with minimum <index> (in our exaple we woult have DDD as result).

I have tried the following expression but it seams to not work:

/root/obj[datalist/data/code='X'][not(preceding-sibling::obj/index <= index)
and not(following-sibling::obj/index <= index)]/datalist/data/value

but it does not work


Solution

  • After quite a while of staring at this I think I've figured out what's up. In short, you're enforcing code='X' in the initial match for obj, but not in the sibling axes.

    In other words, you're saying: "Find me a obj node which a) has no siblings with a lower index, and b) has the descendant code='X'. No nodes meet these criteria.

    Of course you meant to consider only siblings that also had the descendant code='X', not just any sibling.

    Try this (runnable at this XML Playground)

    root/obj[datalist/data/code='X'][
        not(preceding-sibling::obj[
            datalist/data/code='X'
        ]/index &lt; index)
        and
        not(following-sibling::obj[
            datalist/data/code='X'
        ]/index &lt; index)
    ]/datalist/data/value