XPath to select parent containing only specific type of children?

Viewed 61

I have this simple DOM :

<r>
  <a1>
    <foo>...</foo>
    <foo>...</foo>
    <foo>...</foo>
  </a1>
  <a2>
    <faa>...</faa>
    <faa>...</faa>
    <foo>...</foo>
  </a2>
  <a3>
    <fii>...</fii>
    <fii>...</fii>
    <fii>...</fii>
  </a3>
</r>

Is it possible with only XPath to select the element aX (here in the example, the element a1) containing only foo children elements?

3 Answers

This XPath,

//*[foo][not(*[not(self::foo)])]

selects all elements that have foo child elements and no other child elements.

Explanation

  • //* selects all elements in the document
  • //*[foo] ...that have at least one foo child element
  • //*[foo][not(*[not(self::foo)])] ...and do not have any child elements that are not foo. Since we've already predicated that there must exist a foo child element, by adding that there can be no others that are not a foo child element, we guarantee that there are foo and only foo child elements, as requested.

Use this XPath to get all elements that have "foo" elements as children

//*[foo]

To complete @kjhughes's answer, two working XPath :

//foo[count(preceding-sibling::*)=count(preceding-sibling::foo)]/..
//*[starts-with(name(),"a")][count(.//*)=count(.//foo)]

Output :

<a1>
    <foo>...</foo>
    <foo>...</foo>
    <foo>...</foo>
</a1>
Related