XSLT 1.0 - 条件节点分配

时间:2011-11-15 18:03:16

标签: xslt xpath

使用纯XSLT 1.0,我如何有条件地分配节点。我正在尝试这样的事情,但它没有用。

<xsl:variable name="topcall" select="//topcall"/>
<xsl:variable name="focusedcall" select="//focusedcall" />

<xsl:variable name="firstcall" select="$topcall | $focusedcall"/>

对于变量firstcall,我正在进行条件节点选择。如果有topcall,则将其分配给firstcall,其他人则将firstcall分配给focusedcall

3 个答案:

答案 0 :(得分:5)

这应该有效:

<xsl:variable name="firstcall" select="$topcall[$topcall] |
                                       $focusedcall[not($topcall)]" />

换句话说,如果$topcall nodeset非空,请选择$topcall;如果$focusedcall nodeset为空,则$topcall

关于“它可以是5-6个节点”

重新更新

鉴于可能有5-6个替代品,即除了$ topcall和$ focusedcall之外还有3-4个......

最简单的解决方案是使用<xsl:choose>

<xsl:variable name="firstcall">
  <xsl:choose>
    <xsl:when test="$topcall">    <xsl:copy-of select="$topcall" /></xsl:when>
    <xsl:when test="$focusedcall"><xsl:copy-of select="$focusedcall" /></xsl:when>
    <xsl:when test="$thiscall">   <xsl:copy-of select="$thiscall" /></xsl:when>
    <xsl:otherwise>               <xsl:copy-of select="$thatcall" /></xsl:otherwise>
  </xsl:choose>
</xsl:variable>

但是,在XSLT 1.0中,这会将所选结果的输出转换为结果树片段(RTF:基本上是一个冻结的XML子树)。之后,您将无法在$firstcall上使用任何重要的XPath表达式来从中选择内容。如果您需要稍后在$firstcall上进行XPath选择,例如select="$firstcall[1]",您有几个选择......

  1. 将这些选择放入<xsl:when><xsl:otherwise>,以便在数据转换为RTF之前发生。或者,
  2. 考虑node-set()扩展,它将RTF转换为节点集,因此您可以从中进行正常的XPath选择。此扩展在大多数XSLT处理器中都可用,但不是全部。或者,
  3. 考虑使用XSLT 2.0,其中RTF根本不是问题。实际上,在XPath 2.0中,如果需要,可以将正常的if / then / else条件放在XPath表达式中。
  4. 使用嵌套谓词(如
  5. )在XPath 1.0中实现它

    select="$topcall[$topcall] |
            ($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])[not($topcall)]"
    

    并根据需要继续嵌套。换句话说,在这里我将XPath表达式用于上面的两个替代方案,并用

    替换了$ focusedcall
    ($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])
    

    下一次迭代,您将用

    替换$ thiscall
    ($thiscall[$thiscall] | $thatcall[not($thiscall)])
    

    当然这变得难以阅读,而且容易出错,所以我不会选择这个选项,除非其他选项不可行。

答案 1 :(得分:3)

<xsl:variable name="firstcall" select="($topcall | $focusedcall)[1]"/>能做你想做的吗?这通常是按照不同类型节点的文档顺序获取第一个节点的方法。

答案 2 :(得分:2)

<强>予。 XSLT 1.0解决方案这个简短的(30行)简单参数化转换适用于任意数量的节点类型/名称:

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

 <xsl:param name="pRatedCalls">
   <call type="topcall"/>
   <call type="focusedcall"/>
   <call type="normalcall"/>
 </xsl:param>

 <xsl:variable name="vRatedCalls" select=
  "document('')/*/xsl:param[@name='pRatedCalls']/*"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:variable name="vpresentCallNames">
  <xsl:for-each select="$vRatedCalls">
   <xsl:value-of select=
   "name($vDoc//*[name()=current()/@type][1])"/>
   <xsl:text> </xsl:text>
  </xsl:for-each>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:copy-of select=
   "//*[name()
       =
        substring-before(normalize-space($vpresentCallNames),' ')]"/>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档(请注意文档顺序与pRatedCalls参数中指定的优先级不一致):

<t>
 <normalcall/>
 <focusedcall/>
 <topcall/>
</t>

产生完全正确的结果

<topcall/>

将相同的转换应用于以下XML文档

<t>
 <normalcall/>
 <focusedcall/>
</t>

再次生成想要的正确结果

<focusedcall/>

<强>解释

  1. 要搜索的节点的名称(根据需要和优先级顺序)由名为$pRatedCalls的全局(通常是外部指定的)参数指定。

  2. 在变量$vpresentCallNames的主体中,我们生成一个以空格分隔的元素名称列表,这些元素都被指定为type的{​​{1}}属性的值元素call $ pRatedCalls`参数,也是XML文档中元素的名称。

  3. 最后,我们在这个以空格分隔的列表中确定第一个这样的名称,并选择文档中具有此名称的所有元素。

  4. <强> II。 XSLT 2.0解决方案:

    in the