使用纯XSLT 1.0,我如何有条件地分配节点.我正在尝试这样的事情,但它不起作用.
<xsl:variable name="topcall" select="//topcall"/>
<xsl:variable name="focusedcall" select="//focusedcall" />
<xsl:variable name="firstcall" select="$topcall | $focusedcall"/>
Run Code Online (Sandbox Code Playgroud)
对于变量firstcall,我正在进行条件节点选择.如果有一个topcall然后分配给firstcall,其他人分配firstcall给focusedcall.
这应该工作:
<xsl:variable name="firstcall" select="$topcall[$topcall] |
$focusedcall[not($topcall)]" />
Run Code Online (Sandbox Code Playgroud)
换句话说,选择$topcall如果$topcall节点集不为空; $focusedcall如果$topcallnodeset为空.
关于"它可以是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>
Run Code Online (Sandbox Code Playgroud)
但是,在XSLT 1.0中,这会将所选结果的输出转换为结果树片段(RTF:基本上是一个冻结的XML子树).之后,您将无法使用任何重要的XPath表达式$firstcall从中选择内容.如果您需要$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)]"
Run Code Online (Sandbox Code Playgroud)
并根据需要继续筑巢.换句话说,在这里我将XPath表达式用于上面的两个替代方案,并替换了$ focusedcall
($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])
Run Code Online (Sandbox Code Playgroud)
下一次迭代,你将用$替换$ thiscall
($thiscall[$thiscall] | $thatcall[not($thiscall)])
Run Code Online (Sandbox Code Playgroud)
等等
当然这变得难以阅读,并且容易出错,所以除非其他人不可行,否则我不会选择此选项.
I. 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>
Run Code Online (Sandbox Code Playgroud)
当应用于此 XML 文档时(请注意文档顺序与参数中指定的优先级不一致pRatedCalls):
<t>
<normalcall/>
<focusedcall/>
<topcall/>
</t>
Run Code Online (Sandbox Code Playgroud)
产生完全想要的正确结果:
<topcall/>
Run Code Online (Sandbox Code Playgroud)
当相同的转换应用于以下 XML 文档时:
<t>
<normalcall/>
<focusedcall/>
</t>
Run Code Online (Sandbox Code Playgroud)
再次产生想要的正确结果:
<focusedcall/>
Run Code Online (Sandbox Code Playgroud)
解释:
要搜索的节点的名称(根据需要搜索多个节点并按优先级顺序)由名为 的全局(通常是外部指定的)参数指定$pRatedCalls。
在变量体内,$vpresentCallNames我们生成一个以空格分隔的元素名称列表,这些元素名称既指定为元素$pRatedCalls`type参数的属性值,也是 XML 文档中元素的名称。callin the
最后,我们确定此空格分隔列表中的第一个此类名称,并选择文档中具有此名称的所有元素。
二. 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:param name="pRatedCalls" select=
"'topcall', 'focusedcall', 'normalcall'"/>
<xsl:template match="/">
<xsl:sequence select=
"//*
[name()=$pRatedCalls
[. = current()//*/name()]
[1]
]"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)