2013-08-26 3 views
1

С XPath (.NET) я пытаюсь выбрать все узлы, которые не содержат текстового узла.Поиск всех узлов без текстового узла

Учитывая этот документ:

<root> 
    <node1> 
    <node1a>Node 1A</node1a> 
    </node1> 
    <node2>Node 2</node2> 
    <node3> 
    <node3a>Node 3A</node3a> 
    <node3b></node3b> 
    </node3> 
    <node4></node4> 
    <node5> 
    <node5A></node5A> 
    </node5> 
</root> 

Я Tyring, чтобы получить узлы:

<node3b></node3b> 

<node4></node4> 

<node5> 
    <node5A></node5A> 
</node5> 

Обратите внимание, что перекрывающие поддеревья объединены, так node5A не должны быть возвращены по отдельности.

Я бы ожидать, что это тянуть трюк, но по какой-то причине (что, вероятно, очевидно, когда кто-то указывает на это) он не делает:

//*[count(//text()) = 0] 

Примечание: Я использую XPath tester попробовать вещи вне.

ответ

1

Предположим, что ваш результат пример действительно то, что вы хотите (что не полностью в соответствии с заявлением в названии) предложения выше

//*[count(.//text()) = 0] 

или предпочтительный способ

//*[not(.//text())] 

не ли работа в результате не так, как вы ожидали

<node3b /> 
<node4 /> 
<node5> 
    <node5A /> 
</node5> 
<node5A /> <!-- this node is not present in your example --> 

Если все, что вы хотите, ubtrees без какого-либо текстового узла, не включенного в другие в результате поддеревьев раствор этот

//*[not(.//text())][not(ancestor::*[not(.//text())])] 

Второй предикат удалить из результата все узлы, которые, по крайней мере один предок уже включены в результате

+0

Приятный nitpicking там;) Мне нужны поддеревья, и я редактировал вопрос. –

2

Arg ... и только при проводке, решение выплывает:

//*[count(.//text()) = 0] 

Объяснение: условие count(//text()) = 0 подсчитывает все текстовые узлы от корня, который всегда больше нуля. Для подсчета с текущего узла мне нужно было префикс точки: count(.//text()) = 0

Обратите внимание, что @jvverde правильно отмечает, что узлы могут встречаться несколько раз в результирующем наборе. Таким образом, это выражение не точное совпадение условий, которые я упоминаю, так как node5A находится там дважды:

<node3b></node3b> 

<node4></node4> 

<node5> 
    <node5A></node5A> 
</node5> 

<node5A></node5A> 
1

Вы также можете использовать //*[.=''], насколько пустой элемент должен иметь пустое значение строки.

+2

Это должно сначала вычислите строку данных и может быть намного дороже, чем подсчет текстовых узлов. –

0

Вы также можете использовать более простой и читаемый

//*[not(.//text())] 

или заменить not(...) на empty(...), если вы предпочитаете.

Оба уже оптимизированы, поэтому даже простые реализации XPath должны быть способны реализовать их «с ошибкой» (найденный один текстовый узел, оценивая предикат на false).

+0

Я экспериментировал с «не», прежде чем понял, где виновник в моем выражении. Я попробую ваше предложение, так что вы можете получить вознаграждение;) –

Смежные вопросы