For an XSLT template, I need an XPath expression targeting elements which have a specific child element, but no text nodes.
<!-- 1: matches -->
<a><b/></a>
<!-- 2: does not match -->
<a>foo bar quux<b/></a>
<!-- 3: does not match -->
<a>whatever <b/> further text</a>
<!-- 4: does not match -->
<a>whatever <b/> further text <b/></a>
<!-- 5: does not match -->
<a><x/><b/></a>
<!-- 6: does not match -->
<a>foo bar quux</a>
I came up with a[*[1 = last() and name() = 'b']]
, but then case 2 or 3 are matched when they should not. The reason, of course, is that the *
selects elements and does not care about text nodes. So how do I do this instead?
You could just use
a[count(*)=1 and b and not(text())]
If you are only looking for one b, no other elements and no text. Bear in mind that if you have a carriage return in your xml, some processors will take that as text.
a[b and not(text() or *[2])]
This selects every a
child of the current node (context node) that has a b
child, and doesn't have any text node children or a second element child.
If you also don't want to have any PI or comment children, you can use a shorter version:
a[b and not(node()[2])]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With