Maybe
*[local-name() = 'A' and not(descendant::*[local-name() = 'B'])]
?
Also, there should be only one root element, so for /A[...]
you’re either getting all your XML back or none. Maybe //A[not(B)]
or /*/A[not(B)]
?
I don’t really understand why /A[not(B)]
doesn’t work for you.
~/xml% xmllint ab.xml
<?xml version="1.0"?>
<root>
<A id="1">
<B/>
</A>
<A id="2">
</A>
<A id="3">
<B/>
<B/>
</A>
<A id="4"/>
</root>
~/xml% xpath ab.xml '/root/A[not(B)]'
Found 2 nodes:
-- NODE --
<A id="2">
</A>
-- NODE --
<A id="4" />