Search code examples
xmlbashxpathxmlstarlet

XPath to select parent element if child element is missing


I have some XML like this: some.xml:

<one>
  <two>
    <three> 
    <four>some text</four>
    </three>
  </two>
  <two>
    <three>
        <four>some other text</four>
    </three>
  </two>
  <two>
  </two>
</one>

I can delete any of the two elements by searching for a text:

xmlstarlet ed -d "//one/two[contains(.,'some text')]" some.xml

This removes the first two node. But I want to delete all two elements that do not contain any three element, like this:

<one>
  <two>
    <three> 
    <four>some text</four>
    </three>
  </two>
  <two>
    <three>
        <four>some other text</four>
    </three>
  </two>
</one>

Solution

  • The answer depends on whether by "contains any three element" you mean (1) or (2)

    1. As an immediate child:

      //one/two[not(three)]
      

      will select all two elements that do not have a three child.

    2. As any descendent

      //one/two[not(.//three)]
      

      will select all two elements that do not have a three descendent.