Выбор братьев и сестер между двумя узлами с использованием XPath
Как мне выбрать все таблицы между таблицей, id которой является 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]]
, но это не сработало.
Ответы
Ответ 1
Я считаю, что это выражение XPath выбирает нужные вам узлы:
//table[@class="header_completed"]/
following-sibling::table[@align="center"][1]/
preceding-sibling::table[
preceding-sibling::table[@class="header_completed"]
]
Сначала я перехожу к table
с помощью @class="header_completed"
.
Оттуда я выбираю первую следующую таблицу для сиблинга с @align="center"
.
Оттуда я выбираю все предыдущие родственные таблицы, у которых есть предыдущий брат, который является таблицей с @class="header_completed"
.
Ответ 2
Используйте метод Kayessian для node -set-пересечения:
Пересечение двух node -sets $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
:
/*/*[@class='header_completed'][1]
/following-sibling::*
$ns2
:
/*/*[@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"/>