0

我希望使用包含的 for-each 循环构造一个 XSL 节点集变量。重要的是,构建的节点集是原始(选定的)节点集,而不是副本。

这是我的问题的一个非常简化的版本(当然可以通过选择来解决,但这不是问题的重点)。我已经使用 <name> 节点来测试构造的节点集变量实际上是在原始树中而不是副本中。

XSL 版本 1.0,处理器是 msxsl。

非工作 XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1" omit-xml-declaration="yes" />

<xsl:template match="/">

    <xsl:variable name="entries">
        <xsl:for-each select="//entry">
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="entryNodes" select="msxsl:node-set($entries)"/>

    <xsl:for-each select="$entryNodes">
        <xsl:value-of select="/root/name"/>
        <xsl:value-of select="."/>
    </xsl:for-each>

</xsl:template>

</xsl:stylesheet>

XML 输入:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <name>X</name>
    <entry>1</entry>
    <entry>2</entry>
</root>

想要的输出:

X1X2

实际输出:

12

当然(或一个)问题是副本,但我无法解决这个问题。

4

3 回答 3

1

我希望使用包含的 for-each 循环构造一个 XSL 节点集变量。

我不知道那是什么意思。

重要的是,构建的节点集是原始(选定的)节点集,而不是副本。

这部分我我理解得更好一些。看来您需要更换:

<xsl:variable name="entries">
    <xsl:for-each select="//entry">
        <xsl:copy-of select="."/>
    </xsl:for-each>
</xsl:variable>

和:

<xsl:variable name="entries" select="//entry"/>

或者,最好:

<xsl:variable name="entries" select="root/entry"/>

结果变量是原始节点的节点集entry,因此您可以简单地执行以下操作:

<xsl:for-each select="$entries">
    <xsl:value-of select="/root/name"/>
    <xsl:value-of select="."/>
</xsl:for-each>

得到你预期的结果。

当然,您可以通过在原始上下文中直接在原始节点上进行操作来做同样的事情 - 不需要变量。


针对您发表的评论:

我们显然需要一个更好的例子,但我想我对你想要去哪里有一个模糊的想法。但有几点你必须先了解:

1.
为了在原始上下文中构造一个包含节点集的变量,您必须使用select. 这对您可以选择的内容没有任何限制。您可以一次进行所有选择,也可以分阶段进行,甚至可以循环进行(这里我的意思是真正的循环)。您可以以任何组合方式组合您所做的中间选择:并集、交集或差异。但是您必须select在所有这些步骤中使用,否则您将得到一组新节点,不再具有它们在源树中所做的上下文。

copyIOW,使用和之间的唯一区别select是前者会创建新节点,这正是您希望避免的。

2.
xsl:for-each不是循环。它没有等级或年表。所有节点都是并行处理的,并且没有办法在当前节点中使用先前迭代的结果——因为没有迭代是“先前”的。

如果您尝试使用xsl:for-each以将 n 个已处理节点中的每一个添加到预先存在的节点集中,您最终将得到 n 个结果,每个结果都包含与已处理节点之一连接的预先存在的节点集。

3.
我想你会发现 XPath 语言非常强大,它允许你选择你想要的节点,而不必经过你所暗示的复杂循环。

于 2015-02-20T15:08:31.423 回答
1

XSLT 1.0 中没有“解决方法”——这正是它应该如何工作的。当您有一个使用 content 而不是 a 声明的变量时,select该 content 是由新创建的节点组成的结果树片段(即使这些节点是原始树中节点的副本)。如果要引用附加到原始树的原始节点,则必须使用select. 一个更好的问题是详细说明实际问题并询问您如何编写合适的select表达式来找到您想要的节点而无需使用for-each- 大多数使用xsl:iforxsl:choose可以替换为适当构造的谓词,可能涉及明智地使用xsl:key等。


在 XSLT 2.0 中,它更加灵活。节点集和结果树片段之间没有区别,并且 an 的内容xsl:variable被视为通用“序列构造函数”,如果您构造或复制它们,它可以为您提供新节点:

<xsl:variable name="example" as="node()*">
  <xsl:copy-of select="//entry" />
</xsl:variable>

或原始节点,如果您使用xsl:sequence

<xsl:variable name="example" as="node()*">
  <xsl:sequence select="//entry" />
</xsl:variable>
于 2015-02-20T15:26:46.560 回答
0

如果您向我们展示了一个在 XSLT 1.0 中无法轻松解决的问题,这可能会有所帮助。您无法按照您要求的方式解决您的问题:XSLT 1.0 中没有等效的 xsl:sequence。但是您向我们展示的问题可以在没有这种结构的情况下解决。所以请解释为什么你需要你所要求的。

于 2015-02-20T15:49:28.130 回答