XPath - Получить узел без дочернего элемента определенного типа - PullRequest
59 голосов
/ 14 мая 2009

XML: /A/B или /A

Я хочу получить все A узлы, у которых нет B дочерних элементов.

Я пробовал

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

без успеха

Я предпочитаю решение с синтаксисом /*[local-name()="A" and .... ], если это возможно. Есть идеи, которые работают?

Разъяснение. XML выглядит так:

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

или

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

Ответы [ 5 ]

44 голосов
/ 14 мая 2009

Может быть, *[local-name() = 'A' and not(descendant::*[local-name() = 'B'])]

Кроме того, должен быть только один корневой элемент, поэтому для /A[...] вы либо получаете весь свой XML обратно, либо ни одного. Может быть //A[not(B)] или /*/A[not(B)]?

Я не очень понимаю, почему /A[not(B)] не работает для вас.

~/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" />
14 голосов
/ 02 июня 2011

Попробуйте это "/A[not(.//B)]" или это "/A[not(./B)]".

10 голосов
/ 14 мая 2009

Первое / вызывает запуск XPath в корне документа, я сомневаюсь, что это именно то, что вы хотели.

Возможно, вы имели в виду // A [не (B)], который найдет все узлы A в документе на любом уровне, у которого нет прямого B-потомка.

Или, возможно, вы уже находитесь в узле, который содержит узлы A, и в этом случае вы просто хотите A [не (B)] в качестве XPath.

3 голосов
/ 14 мая 2009

Если вы пытаетесь получить A где-нибудь в иерархии от корня, это работает (для xslt 1.0, а также 2.0, если он используется в xslt)

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

ИЛИ вы также можете сделать

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

ИЛИ также

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

В xslt нет способов добиться того же.

Примечание: XPaths чувствительны к регистру, поэтому, если имена ваших узлов отличаются (что, я уверен, никто не будет использовать A, B), тогда, пожалуйста, убедитесь, что регистр совпадает.

2 голосов
/ 10 сентября 2013

Используйте это:

/*[local-name()='A' and not(descendant::*[local-name()='B'])]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...