XPath Zaznacz wszystkie elementy pomiędzy dwoma określonymi elementami

Mam następujący xml:

<doc>
    <divider />
    <p>text</p>
    <p>text</p>
    <p>text</p>
    <p>text</p>
    <p>text</p>
    <divider />
    <p>text</p>
    <p>text</p>
    <divider />
    <p>text</p>
    <divider />
</doc>

Chcę zaznaczyć wszystkie węzły p po pierwszym elemencie dzielącym aż do następnego wystąpienia elementu dzielącego. Próbowałem z następującym xpath:

//divider[1]/following-sibling::p[following::divider]

Ale problem polega na tym, że wybiera wszystkie elementy p przed ostatnim elementem dzielącym. Nie jestem pewien jak to zrobić używając xpath 1.

Author: Mirko, 2012-06-02

4 answers

Ta sama koncepcja co bytebuster, ale inna xpath:

/*/p[count(preceding-sibling::divider)=1]
 33
Author: Daniel Haley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 04:50:36

Oto ogólne wyrażenie XPath :

/*/divider[$k]
    /following-sibling::p
       [count(.|/*/divider[$k+1]/preceding-sibling::p)
       =
        count(/*/divider[$k+1]/preceding-sibling::p)
       ]

Jeśli zamienisz $k na 1, wybierane są dokładnie żądane p węzły.

Jeśli zamienisz $k na 2 wtedy wszystkie p elementy między 2. a 3. divider,..., itd.

Wyjaśnienie :

Jest to proste zastosowanie Kayessian formuły XPath 1.0 Dla przecięcia zestawu węzłów:

$ns1[count(.|$ns2) = count($ns2)]

Wybiera wszystkie węzły, które należą zarówno do nodesetów $ns1 jak i $ns2.

W tym konkretnym przypadku zamieniamy $ns1 na:

/*/divider[$k]/following-sibling::p

I zamieniamy $ns2 na:

/*/divider[$k+1]/preceding-sibling::p
 20
Author: Dimitre Novatchev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 05:09:42

Myślę, że jest o wiele prostsze i prawdopodobnie szybsze rozwiązanie: chcesz, aby wszystkie poprzednie rodzeństwo drugiego dzielnika miało przynajmniej jeden poprzedni dzielnik rodzeństwa:

/doc/divider[2]/preceding-sibling::p[preceding-sibling::divider]

Robi się to trochę bardziej złożone, oczywiście, jeśli chcesz znaleźć paras między drugim i trzecim dzielnikiem: wtedy chcesz coś bardziej podobnego do rozwiązania Daniela Haleya.

 7
Author: Michael Kay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 23:36:22

A co z zaznaczeniem WSZYSTKICH p mających dokładnie Jeden element divider jako preceding-sibling ?

//doc/p[preceding-sibling::divider[1] and not (preceding-sibling::divider[2])]
 5
Author: bytebuster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 04:21:40