Search code examples
xmlxpathxmllint

Get child value if another child value matches


I have an XML file I need to parse from the shell. It looks somewhat like this:

<?xml version="1.0" encoding="UTF-8"?>
<things>
    <thing>
        <foo>123</foo>
        <bar>false</bar>
    </thing>
    <thing>
        <bar>true</bar>
        <foo>abc</foo>
    </thing>
</things>

Note that the order of the child nodes of things is arbitrary. In my real-world data, there are a couple of other child nodes inside each thing.

Now, the value of foo is unique. I need to get the value of the child node bar for the thing whose child foo's value is, say, abc. I've tried to use an XPath query with xmllint but no luck. I can't get a match; or, if I just test with a more general query, I get the entire tree.

$ xmllint --pattern //thing[foo='abc']/bar test.xml
xmllint: No match.
$ xmllint --pattern //thing/bar test.xml
(the whole tree)

I was hoping just to get true.

What am I doing wrong? I don't have access to the --xpath flag other questions mention, so if that's the answer then I'm out of luck.


Solution

  • Try this command:

    xmllint --xpath '//thing[foo="abc"]/bar/text()' test.xml
    

    Another command:

    echo 'cat //thing[foo="abc"]/bar/text()' | xmllint --shell test.xml
    

    Also try xmlstarlet:

    xmlstarlet sel -t -m '//thing[foo="abc"]/bar' -v 'text()' test.xml