Выбор одноуровневых элементов между двумя узлами с помощью XPath

Как я выбрал бы все таблицы между таблицей, идентификатор которой является header_completed и первой таблицей после той header_completed, которая имеет выравнивание центра? Вот HTML, из которого я выбираю его:

<table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920" align="center" class="header_completed"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920"></table> <--
<table border="0" cellpadding="0" cellspacing="0" width="920"></table> <--
<table border="0" cellpadding="0" cellspacing="0" width="920"></table> <-- these 5
<table border="0" cellpadding="0" cellspacing="0" width="920"></table> <--
<table border="0" cellpadding="0" cellspacing="0" width="920"></table> <--
<table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920"></table>
<table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>

Я пытался использовать //table[@id="header_completed"]/following-sibling::node()[following-sibling::table[@align="center"][1]] но это не работало.

27
задан bakkal 6 August 2010 в 23:13
поделиться

2 ответа

Я считаю, что это выражение XPath выбирает нужные вам узлы:

//table[@class="header_completed"]/
    following-sibling::table[@align="center"][1]/
        preceding-sibling::table[
            preceding-sibling::table[@class="header_completed"]
        ]

Сначала я перехожу к таблице с помощью @ class = "header_completed" .

Оттуда я выбираю первую соседнюю таблицу с @ align = "center" .

Отсюда я выбираю все предыдущие одноуровневые таблицы, у которых есть предыдущий одноуровневый объект, которым является таблица с @ class = "header_completed" .

28
ответ дан 28 November 2019 в 04:56
поделиться

Используйте метод Кейесса для пересечения узловых наборов:

Пересечение двух узловых наборов $ns1 и $ns2 оценивается следующим выражением XPath:

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

Если у нас есть следующий XML документ:

<t>
    <table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920" align="center" class="header_completed"></table>
    <table border="0" cellpadding="0" cellspacing="1" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="2" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="3" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="4" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="5" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920"></table>
    <table border="0" cellpadding="0" cellspacing="0" width="920" align="center"></table>
</t>

то, согласно вопросу, мы имеем:

$ns1 is:

/*/*[@class='header_completed'][1]
                     /following-sibling::*

$ns2 is:

/*/*[@class='header_completed'][1]
             /following-sibling::*[@align='center'][1]
                   /preceding-sibling::*

Мы просто подставляем $ns1 и $ns2 в формулу Кайесса и получаем следующее выражение XPath, которое выбирает именно нужные 5 элементов:

/*/*[@class='header_completed'][1]
                         /following-sibling::*
              [count(.|/*/*[@class='header_completed'][1]
                            /following-sibling::*[@align='center'][1]
                               /preceding-sibling::*)
              =
               count(/*/*[@class='header_completed'][1]
                            /following-sibling::*[@align='center'][1]
                                /preceding-sibling::*)
              ]

Чтобы проверить, что это действительно решение, мы используем следующее XSLT-преобразование:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="ns1" select=
      "/*/*[@class='header_completed'][1]
                         /following-sibling::*
      "/>
    <xsl:variable name="ns2" select=
       "/*/*[@class='header_completed'][1]
                 /following-sibling::*[@align='center'][1]
                       /preceding-sibling::*
       "/>

    <xsl:template match="/">
        <xsl:copy-of select=
       "$ns1[count(.| $ns2)=count($ns2)]
       "/>
        <DELIMITER/>
        <xsl:copy-of select=
       "/*/*[@class='header_completed'][1]
                         /following-sibling::*
              [count(.|/*/*[@class='header_completed'][1]
                            /following-sibling::*[@align='center'][1]
                               /preceding-sibling::*)
              =
               count(/*/*[@class='header_completed'][1]
                            /following-sibling::*[@align='center'][1]
                                /preceding-sibling::*)
              ]
       "/>
    </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к XML-документу выше, получается искомый правильный результат:

<table border="0" cellpadding="0" cellspacing="1" width="920"/>
<table border="0" cellpadding="0" cellspacing="2" width="920"/>
<table border="0" cellpadding="0" cellspacing="3" width="920"/>
<table border="0" cellpadding="0" cellspacing="4" width="920"/>
<table border="0" cellpadding="0" cellspacing="5" width="920"/>
<DELIMITER/>
<table border="0" cellpadding="0" cellspacing="1" width="920"/>
<table border="0" cellpadding="0" cellspacing="2" width="920"/>
<table border="0" cellpadding="0" cellspacing="3" width="920"/>
<table border="0" cellpadding="0" cellspacing="4" width="920"/>
<table border="0" cellpadding="0" cellspacing="5" width="920"/>

XPath 2. 0 решение:

В XPath 2.0 мы можем использовать оператор intersect и операторы >> и/или <<.

Выражение XPath 2.0, соответствующее ранее использованному выражению XPath 1.0, имеет вид:

     /*/*[ .
        >>
         /*/*[@class='header_completed'][1]
         ]

  intersect

    /*/*[ /*/*[@class='header_completed'][1]
                 /following-sibling::*[@align='center'][1]
             >>
              .
        ]

Вот решение XSLT 2.0, доказывающее правильность этого выражения XSLT 2.0:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="ns1" select=
  "/*/*[ .
        >>
         /*/*[@class='header_completed'][1]
       ]
  "/>

    <xsl:variable name="ns2" select=
       "/*/*[ /*/*[@class='header_completed'][1]
                 /following-sibling::*[@align='center'][1]
             >>
              .
             ]
       "/>

 <xsl:template match="/">
   <xsl:sequence select="$ns1 intersect $ns2"/>
  <DELIMITER/>
   <xsl:sequence select=
   "/*/*[ .
        >>
         /*/*[@class='header_completed'][1]
       ]

  intersect

    /*/*[ /*/*[@class='header_completed'][1]
                 /following-sibling::*[@align='center'][1]
             >>
              .
        ]
   "/>
 </xsl:template>
</xsl:stylesheet>

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

<table border="0" cellpadding="0" cellspacing="1" width="920"/>
<table border="0" cellpadding="0" cellspacing="2" width="920"/>
<table border="0" cellpadding="0" cellspacing="3" width="920"/>
<table border="0" cellpadding="0" cellspacing="4" width="920"/>
<table border="0" cellpadding="0" cellspacing="5" width="920"/>
<DELIMITER/>
<table border="0" cellpadding="0" cellspacing="1" width="920"/>
<table border="0" cellpadding="0" cellspacing="2" width="920"/>
<table border="0" cellpadding="0" cellspacing="3" width="920"/>
<table border="0" cellpadding="0" cellspacing="4" width="920"/>
<table border="0" cellpadding="0" cellspacing="5" width="920"/>
28
ответ дан 28 November 2019 в 04:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: