Используйте метод Кейсиана пересечения множества узлов :
Пересечение двух наборов узлов $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"/>