web-dev-qa-db-fra.com

XPath - Obtenir un nœud sans enfant de type spécifique

XML: /A/B Ou /A

Je veux obtenir tous les nœuds A qui n'ont pas d'enfants B.

J'ai essayé

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

sans succès

Je préfère une solution avec la syntaxe /*[local-name()="A" and .... ], si possible. Des idées qui fonctionnent?

Clarification. Le xml ressemble à:

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

ou

<WhatEver>
  <A></A>
</WhatEver>
61
Martin Bring

Peut-être *[local-name() = 'A' and not(descendant::*[local-name() = 'B'])]?

De plus, il ne devrait y avoir qu'un seul élément racine, donc pour /A[...] Vous récupérez tout votre XML ou aucun. Peut-être //A[not(B)] ou /*/A[not(B)]?

Je ne comprends pas vraiment pourquoi /A[not(B)] ne fonctionne pas pour vous.

~/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" />
45
alamar

Essayez cette "/A[not(.//B)]" ou cette "/A[not(./B)]".

14
Serhiy

Le premier/fait démarrer XPath à la racine du document, je doute que c'est ce que vous vouliez.

Peut-être que vous vouliez dire // A [pas (B)] qui trouverait tous les nœuds A dans le document à n'importe quel niveau qui n'ont pas d'enfant B direct.

Ou peut-être que vous êtes déjà sur un nœud qui contient des nœuds A, auquel cas vous voulez juste A [pas (B)] comme XPath.

10
AnthonyWJones

Si vous essayez d'obtenir A n'importe où dans la hiérarchie à partir de la racine, cela fonctionne (pour xslt 1.0 ainsi que 2.0 au cas où il serait utilisé dans xslt)

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

OU vous pouvez aussi faire

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

OU aussi

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

Il n'y a aucun moyen dans xslt pour réaliser la même chose.

Remarque: les XPath sont sensibles à la casse, donc si vos noms de nœuds sont différents (ce qui, j'en suis sûr, personne n'utilisera A, B), alors assurez-vous que la casse correspond.

3
Rashmi Pandit

Utilisez ceci:

/*[local-name()='A' and not(descendant::*[local-name()='B'])]
2
Cobaia