使用纯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
。
答案 0 :(得分:5)
这应该有效:
<xsl:variable name="firstcall" select="$topcall[$topcall] |
$focusedcall[not($topcall)]" />
换句话说,如果$topcall
nodeset非空,请选择$topcall
;如果$focusedcall
nodeset为空,则$topcall
。
重新更新:
鉴于可能有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]"
,您有几个选择......
<xsl:when>
或<xsl:otherwise>
,以便在数据转换为RTF之前发生。或者,node-set()
扩展,它将RTF转换为节点集,因此您可以从中进行正常的XPath选择。此扩展在大多数XSLT处理器中都可用,但不是全部。或者,
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/>
<强>解释强>:
要搜索的节点的名称(根据需要和优先级顺序)由名为$pRatedCalls
的全局(通常是外部指定的)参数指定。
在变量$vpresentCallNames
的主体中,我们生成一个以空格分隔的元素名称列表,这些元素都被指定为type
的{{1}}属性的值元素call
$ pRatedCalls`参数,也是XML文档中元素的名称。
最后,我们在这个以空格分隔的列表中确定第一个这样的名称,并选择文档中具有此名称的所有元素。
<强> II。 XSLT 2.0解决方案:
in the