Allpointsw
Allpointsw

Reputation: 11

xpath of xmllint output

I have some xml documents that I want to do xquery operations on. xmllint appears to almost do what I want by returning the nodes that match the query. This does not help me since this node may exist many places and I'm left not knowing where the matches are.

A very simple example is xmllint -xpath '//shutdown[text()="false"]' returns: <shutdown>false</shutdown><shutdown>false</shutdown><shutdown>false</shutdown><shutdown>false</shutdown><shutdown>false</shutdown>.

This tells me there are matching nodes but not which nodes. Is there some method for getting the actual xpath of the returned nodes? I have not been able to find anything.

While the example given could also be done greping the xml document from within an editor, this approach is not possible with more complex queries.

Upvotes: 1

Views: 2163

Answers (2)

Content of test.xml:

<l0>
<l1>
    <l1-1>
        <shutdown>true</shutdown>
    </l1-1>
    <l1-2>
        <shutdown>false</shutdown>
    </l1-2>
</l1>
<l2>
    <l2-1>
        <shutdown>false</shutdown>
    </l2-1>
</l2></l0>

Shell Script:

#!/bin/s

xpath="//shutdown[text()='false']"
count=$(echo "xpath ${xpath}" |xmllint --shell test.xml |grep ELEMENT|wc -l)

x=1
while [ $x -lt `expr $count + 1` ]
do
    parents=`       echo "xpath (${xpath})[${x}]/ancestor::*" | \
                    xmllint --shell test.xml| \
                    grep "ELEMENT" |\
                    sed "s/.*ELEMENT//"|\
                    sed ':a;N;$!ba;s/\n/ -> /g'`
    echo "${parents} -> shutdown(false)[${x}]"
    x=`expr $x + 1`
done

Results:

 l0 ->  l1 ->  l1-2 -> shutdown(false)[1]
 l0 ->  l2 ->  l2-1 -> shutdown(false)[2]

Upvotes: 0

Jens Erat
Jens Erat

Reputation: 38662

This is not possible with plain XPath 1.0 as supported by xmllint (which does not support XQuery as you tagged the question!). XPath 3.0 (and also XQuery 3.0) would have support for fn:path($element) as proposed by @dirkk. XPath 1.0 can only be used to select whole subtrees (including single elements, text nodes, attributes, ...), but not create new results from your XML documents.

You'll have to use a more powerful language like XQuery or anything else to further work on the XPath result of an ancestor-or-self axis step, which contains all elements along the path and join the element names:

An XQuery example:

string-join(
  (
    (: root node :)
    "",
    (: following steps :)
    for $step in //path/to/element/ancestor-or-self::*
    return name($step)
  ),
  "/"
)

Similar could be performed with arbitrary scripting languages, I also proposed a PHP equivalent in another question, additionally even using positional predicates for specific paths (this could be easily removed from the code again).

Upvotes: 0

Related Questions