使用取决于测试将节点分配给xsl:变量

时间:2012-03-30 17:09:01

标签: xslt xslt-1.0

我对xslt完全不熟悉,所以如果这是一个愚蠢的问题,请原谅。 我需要声明一个变量并将其指向xml中2个可能的节点之一,具体取决于它们实际存在的位置。我正在尝试以下方法:

<xsl:variable name="DealNode">
    <xsl:choose>
        <xsl:when test="/AllResponse/Deals/Deal"><xsl:copy-of select="/AllResponse/Deals/Deal"/></xsl:when>
        <xsl:otherwise><xsl:copy-of select="/AllResponse/BookDeals/BookDeal"/></xsl:otherwise>
    </xsl:choose>
</xsl:variable>

这似乎有效,因为DealNode确实看起来像我期望的那样。但是,如果我现在这样做:

<xsl:variable name="TradeNode" select="$DealNode/Trades/Trade"/>

TradeNode仍为空。我做错了什么?

示例xml:

<AllResponse>
    <Deals>
        <Deal>
            <Trades>
                <Trade>
                </Trade>
            </Trades>
        </Deal>
    </Deals>
</AllResponse>

3 个答案:

答案 0 :(得分:3)

目前接受的答案存在严重问题。如果根据以下XML文档评估其XPath表达式

<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]

不会选择联合的第一个参数,而是完全相反的(第二个参数)。

这样做的原因是union操作的结果总是按其节点的文档顺序排序 - 换句话说,节点集是一个集而不是一个序列。

这是一个正确的解决方案

<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文档应用此转换时,将选择所需的正确结果(作为union运算符的第一个参数的节点),并输出此选择的结果:

<Deal>
   <Trades>
      <Trade/>
   </Trades>
</Deal>

解释:当条件$ns1$cond并选择true()时,我们要选择$ns2时使用的正确通用表达式如果$cond为false,则为:

$ns1[$cond] | $ns2[not($cond)]

在我们的具体案例中:

$ns1/*/Deals/Deal

$ns2/*/BookDeals/BookDeal

$condboolean(/*/Deals/Deal)

在上面的一般表达中替换这些,并缩短

/*/Deals/Deal[/*/Deals/Deal]

为:

/*/Deals/Deal

我们到达了此答案中使用的表达

/*/Deals/Deal | /*[not(Deals/Deal)]/BookDeals/BookDeal

答案 1 :(得分:2)

定义变量的一种方法如下:

<xsl:variable name="DealNode" select="(/AllResponse/Deals/Deal | /AllResponse/BookDeals/BookDeal)[1]"/>

它构成了两个选定节点集的并集,并获取该并集中的第一个节点,以便在第一个表达式选择节点的节点时,如果第一个表达式没有选择任何内容,则选择第一个节点第二个表达式。

答案 2 :(得分:0)

XSLT1不完全支持结果树片段。要执行您尝试的操作需要exsl:node-set()

此外,即使在XSLT2中,正确的XPath也是$DealNode/Deal/Trades/Trade