2010-02-01 14 views

Odpowiedz

52

Jeśli przetłumaczysz "nie są potomkami" na "nie masz przodka", otrzymasz wyrażenie: //*[not(ancestor::X)]. Spowoduje to zwrócenie wszystkich węzłów w dokumencie, które nie są potomkami węzłów o nazwie "X".

16

jarnbjo wskazuje intuicyjny sposób, aby to zrobić, aby użyć //*[not(ancestor::X)]. Ma to ogromną zaletę, że będzie działać niezależnie od tego, jak zbudowany jest twój dokument, i to jest to, czego powinieneś używać w większości przypadków.

Ale jeśli masz bardzo duży dokument, może to być bardzo nieefektywne. To naprawdę kosztowne zapytanie. Mówi procesorowi XPath, aby odwiedził każdy węzeł w dokumencie i zbadał jego węzeł nadrzędny pod kątem obecności elementu o nazwie X. Chociaż możliwe jest, że procesor XPath jest wystarczająco inteligentny, aby wiedzieć, że nie musi odwiedzać potomków X aby ocenić to zapytanie, jest mało prawdopodobne.

Jeśli masz trochę informacji o tym, gdzie znajduje się element X i jesteś ostrożny, możesz napisać bardziej wydajne zapytanie. Na przykład, jeśli X jest dzieckiem elementu najwyższego poziomu, a to ma wiele potomków, to będzie dużo szybciej:

/* | /*/* | /*/*[not(name()='X')]//* 

Że znajdzie element najwyższego poziomu, wszystkie jej bezpośrednimi dzieci, i potomków któregokolwiek z jego najbliższych dzieci nie noszących nazwy X. Nie będzie badać żadnego z potomków X.

Podobnie, jeśli wiesz, że X jest blisko dolnej części drzewa, to zapytanie może być bardziej efektywny:

//*[not(ancestor::*[position() <= 3][X])] 

ponieważ nie zbada całą oś przodka dla każdego węzła to testów tylko jego ostatnie trzy elementy. (Chyba, że ​​procesor XPath jest na tyle głupi, aby zbadać każdy węzeł na osi, gdy jest wykonywanie testów, które wykorzystują position(), co może być.)

Jak powiedziałem, choć większość czasu najprostsza wersja zamierza być najlepiej, a przez większość czasu używam tego samego.

Powiązane problemy