构建而非选择 XSL 节点集变量

Constructing, not selecting, XSL node set variable

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

这是我的问题的简化版本(当然可以用 select 解决,但这不是问题的重点)。我已经使用 节点来测试构造的节点集变量实际上在原始树中而不是副本中。

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

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

I wish to construct an XSL node set variable using a contained for-each loop.

我不知道那是什么意思。

It is important that the constructed node set is the original (a selected) node set, not a copy.

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

<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。您可以一次性完成 selection,也可以分阶段完成,甚至可以循环完成(这里我指的是真正的循环)。您可以以任何方式组合您创建的中间 select 离子集合:并集、交集或差集。但是您必须在所有这些步骤中使用 select,否则您将得到一组新节点,不再具有它们在源树中所做的上下文。

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

2.
xsl:for-each 不是循环。它没有层次结构或年表。所有的节点都是并行处理的,没有办法在当前的节点中使用上一次迭代的结果——因为没有迭代是 "previous" 到另一个。

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

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

XSLT 1.0 中没有 "way around it" - 这正是它应该如何工作的。如果您有一个用内容而不是 select 声明的变量,那么该内容就是一个由新创建的节点组成的结果树片段(即使这些节点是原始树中节点的副本)。如果您想引用原始树上的原始节点,那么您 必须 使用 select 声明变量。一个更好的问题是详细说明实际问题并询问如何编写合适的 select 表达式来查找所需的节点而无需使用 for-each - xsl:if 或 [ 的大多数用途=17=] 可以用适当构造的谓词替换,可能涉及 xsl:key 等的明智使用


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

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

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