Как выбрать эти элементы с помощью Xpath?

У меня есть документ, что-то вроде этого:

<root>
   <A node="1"/>
   <B node="2"/>
   <A node="3"/>
   <A node="4"/>
   <B node="5"/>
   <B node="6"/>
   <A node="7"/>
   <A node="8"/>
   <B node="9"/>
</root>

Используя xpath, как я могу выбрать все элементы B, которые последовательно следуют за данным элементом A?

Это похоже на следующий-silbing::B, за исключением того, что я хочу, чтобы это были только непосредственно следующие элементы.

Если я на A (узел == 1), то я хочу выбрать узел 2. Если я нахожусь на A (узел == 3), то я не хочу ничего выбирать. Если я на A (узел == 4), то я хочу выбрать 5 и 6.

Могу ли я сделать это в xpath? EDIT: находится в операторе выбора таблицы стилей XSL.


EDIT2: я не хочу использовать атрибут node для различных элементов в качестве уникального идентификатора. Я включил атрибут node только для иллюстрации своей точки зрения. В фактическом XML-документе у меня нет атрибута, который я использую в качестве уникального идентификатора. Ключи xpath "following-sibling::UL[preceding-sibling::LI[1]/@node = current()/@node]" в атрибуте узла, а это не то, что мне нужно.


person Cheeso    schedule 11.07.2009    source источник


Ответы (3)


Краткий ответ (при условии, что current() в порядке, так как он помечен как xslt):

following-sibling::B[preceding-sibling::A[1]/@node = current()/@node]

Пример таблицы стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates select="/root/A"/>
    </xsl:template>

    <xsl:template match="A">
        <div>A: <xsl:value-of select="@node"/></div>
        <xsl:apply-templates select="following-sibling::B[preceding-sibling::A[1]/@node = current()/@node]"/>
    </xsl:template>

    <xsl:template match="B">
        <div>B: <xsl:value-of select="@node"/></div>
    </xsl:template>
</xsl:stylesheet>

Удачи!

person Chris Nielsen    schedule 11.07.2009
comment
Так полезно напомнить мне, что current() может помочь позиционировать операторы относительной логики. - person Michael Shopsin; 25.08.2016

Хотя ответ @Chris Nielsen является правильным подходом, он оставляет неопределенность в случаях, когда сравниваемый атрибут не уникален. Более правильный способ решения:

following-sibling::B[
  generate-id(preceding-sibling::A[1]) = generate-id(current())
]

Это гарантирует, что preceding-sibling::A идентично текущему A, а не просто сравнивает значения некоторых атрибутов. Если у вас нет гарантированно уникальных атрибутов, это единственный безопасный способ.

person Tomalak    schedule 13.07.2009
comment
+1; Я собирался сказать следующий-брат::B[count(preceding-sibling::A[1] | current()) = 1], но ваш способ кажется более понятным. - person Chris Nielsen; 13.07.2009
comment
ИМХО, метод count(...) для определения идентификатора узла семантически уступает методу generate-id(), но иногда я использую и его. Немного зависит от контекста, но в целом я предпочитаю generate-id(), потому что он более явный. - person Tomalak; 13.07.2009

Решение может заключаться в том, чтобы сначала собрать все следующие узлы с помощью following-sibling::*, захватить первый из них и потребовать, чтобы он был узлом «B».

following-sibling::*[position()=1][name()='B']
person Søren Løvborg    schedule 11.07.2009