В настоящее время принятый ответ имеет серьезную проблему. Если его выражение XPath оценивается по следующему документу XML :
<AllResponse>
<BookDeals>
<BookDeal>
<Trades>
<Trade>
</Trade>
</Trades>
</BookDeal>
</BookDeals>
<Deals>
<Deal>
<Trades>
<Trade>
</Trade>
</Trades>
</Deal>
</Deals>
</AllResponse>
тогда, вопреки утверждениям в ответе, предоставляется XPath-выражение :
(/AllResponse/Deals/Deal | /AllResponse/BookDeals/BookDeal)[1]
не выбирает первый аргумент объединения, но в точности противоположен (2-й аргумент).
Причина этого заключается в том, что результат операции объединения всегда сортируется по порядку документа его узлов - другими словами, набор узлов - это набор, а не последовательность.
Вот правильное решение :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:variable name="vDealNode" select=
"/*/Deals/Deal | /*[not(Deals/Deal)]/BookDeals/BookDeal"/>
<xsl:copy-of select="$vDealNode"/>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к вышеуказанному XML-документу, выбирается нужный, правильный результат (узел, который является первым аргументом оператора объединения) , и результат этого выбора выводится:
<Deal>
<Trades>
<Trade/>
</Trades>
</Deal>
Объяснение : правильное общее выражение, которое нужно использовать, когда мы хотим выбрать $ns1
, когда условие $cond
равно true()
, и выбрать $ns2
, если $cond
равно false, это:
$ns1[$cond] | $ns2[not($cond)]
В нашем конкретном случае:
$ns1
- это /*/Deals/Deal
,
$ns2
is /*/BookDeals/BookDeal
и
$cond
is boolean(/*/Deals/Deal)
Подставляя их в общее выражение выше и сокращая :
/*/Deals/Deal[/*/Deals/Deal]
до:
/*/Deals/Deal
мы приходим к выражению, используемому в этом ответе :
/*/Deals/Deal | /*[not(Deals/Deal)]/BookDeals/BookDeal