jarnbjo указывает на интуитивный способ сделать это, используя //*[not(ancestor::X)]
. Это имеет очень большое преимущество, поскольку оно будет работать независимо от того, как структурирован ваш документ, и это то, что вы должны использовать в большинстве случаев.
Но если у вас очень большой документ, он может быть крайне неэффективным. Это действительно дорогой запрос. Он сообщает процессору XPath посетить каждый узел в документе и проверить его узел-предок на наличие элемента с именем X. Хотя возможно, что процессор XPath достаточно умен, чтобы знать, что ему не нужно посещать потомков X оценить этот запрос маловероятно.
Если у вас есть некоторая информация о том, где находится элемент X, и вы осторожны, вы можете написать более эффективный запрос. Например, если X является дочерним элементом элемента верхнего уровня и имеет много потомков, это будет намного быстрее:
/* | /*/* | /*/*[not(name()='X')]//*
Он находит элемент верхнего уровня, всех его непосредственных потомков и потомков любого из его непосредственных потомков, не названных X. Он не будет проверять ни одного из потомков X.
Аналогично, если вы знаете, что X находится близко к нижней части дерева, этот запрос может быть более эффективным:
//*[not(ancestor::*[position() <= 3][X])]
потому что он не будет проверять всю ось предка для каждого проверяемого узла, только его последние три элемента. (Если процессор XPath не настолько туп, чтобы проверять каждый узел на оси, когда он выполняет тесты, использующие position()
, которым он может быть.)
Как я уже сказал, в большинстве случаев самая простая версия будет лучшей, и большую часть времени это то, что я использовал бы сам.