tags:

views:

1767

answers:

3

XML: /A/B or /A

I want to get all A nodes that not have any B childs.

I´ve tried

/A[not(B)]
/A[not(exists(B))]

without success

I prefer a solution with the syntax /*[local-name()="A" and .... ], if possible. Any ideas that works?

Clarification. The xml looks like:

<WhatEver>
  <A>
    <B></B>
  </A>
</WhatEver>

or

<WhatEver>
  <A></A>
</WhatEver>

Kind regards
Martin Bring

+3  A: 

Maybe *[local-name() = 'A' and not(descentants::*[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" />
alamar
A: 

The first / causes XPath to start at the root of the document, I doubt that is what you intended.

Perhaps you meant //A[not(B)] which would find all A nodes in the document at any level that do not have a direct B child.

Or perhaps you are already at a node that contains A nodes in which case you just want A[not(B)] as the XPath.

AnthonyWJones
+1  A: 

If you are trying to get A anywhere in the hierarchy from the root, this works (for xslt 1.0 as well as 2.0 in case its used in xslt)

//descendant-or-self::node()[local-name(.) = 'a' and not(count(b))]

OR you can also do

//descendant-or-self::node()[local-name(.) = 'a' and not(b)]

OR also

//descendant-or-self::node()[local-name(.) = 'a' and not(child::b)]

There are n no of ways in xslt to achieve the same thing.

Note: XPaths are case-sensitive, so if your node names are different (which I am sure, no one is gonna use A, B), then please make sure the case matches.

Rashmi Pandit
FYI, the question is about XPath, not XSLT. They are distinct (though related) technologies. Otherwise, your answer is technically correct. As an aside though, "/root/A[not(B)]" works just fine as @Alamar mentioned. ;-)
Cerebrus
Thanks for the correction. I meant xpaths in my last line. Have edited the post. As for "/root/A[not(B)]" I already ran it successfully. But yet posted alternate xpaths as it wasnt working for Martin. Which is also y i mentioned case-sensitivity.
Rashmi Pandit