Search code examples
xmlxpathxmlstarlet

How to list every possible parent elements of a child element in xmlstarlet


Given this data:

<root>
  <A>
    <A1 id="1">
        <elem>apple</elem>
    </A1>
  </A>

  <B>
    <B1 id="2">
        <elem>banana</elem>
    </B1>
  </B>

  <C id="3">
    <elem>grapes</elem>
    <C1></C1>
  </C>
</root>

How do I find out every possible parent elements of the element elem? So far, I am able to find out using -m option by:

$ xmlstarlet sel -t -m '//elem/..' -v 'concat(name(),"=",@id)' -n input3.xml
A1=1
B1=2
C=3

$

But how do I do the same using an xpath expression with -v ? For example, I can only refer to the parent's id attribute but not the parent element's name:

$ xmlstarlet sel -t -v '//elem/../@id' input3.xml
1
2
3
$

Solution

  • You could do:

    xmlstarlet sel -t -v "name(//elem/..)" input3.xml
    

    but that's only going to give you the name of the first match (xmlstarlet is an XPath 1.0 processor).

    The only way to do this, like you found, is by matching (-m) first:

    xmlstarlet sel -t -m "//elem/.." -v "name()" -n input3.xml
    

    although I'd prefer a slightly different XPath:

    xmlstarlet sel -t -m "//*[elem]" -v "name()" -n input3.xml