在 XSLT 2.0 中定义变量时使用 xsl:copy-of

Posted

技术标签:

【中文标题】在 XSLT 2.0 中定义变量时使用 xsl:copy-of【英文标题】:Using xsl:copy-of when defining a variable in XSLT 2.0 【发布时间】:2020-11-21 05:38:10 【问题描述】:

我(在一个虚构的简化世界中)有一个基本的源 XML 结构:

<?xml version="1.0"?>
<library>
  <book>
    <language>french</language>
    <title>Les Misérables</title>
  </book>
  <book>
    <language>english</language>
    <title>Great Expectations</title>
  </book>
</library>

我使用 xsl:variable 的 select 属性定义了一个变量 myVar1

<xsl:variable name="myVar1" select="library/book[language='french']"/>

我在 xsl:variable 中定义了一个带有 xsl:copy-of 的变量 myVar2

    <xsl:variable name="myVar2">
        <xsl:copy-of select="library/book[language='french']"/>
    </xsl:variable>

我希望 myVar1 和 myVar2 相同,但事实并非如此

    <xsl:value-of select="$myVar1/title"/> <!--result: Les Misérables-->
    <xsl:value-of select="$myVar2/title"/> <!--empty result-->

定义 myVar2 时有什么问题?如何表明我希望它作为结构化的可查询变量(如 myVar1)?如果我有几个条件语句来定义变量,使用 select 不方便。

这是完整的 XSLT 文件

<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">

    <xsl:variable name="myVar1" select="library/book[language='french']"/>

    <xsl:variable name="myVar2">
      <xsl:copy-of select="library/book[language='french']"/>
    </xsl:variable>

    <xsl:value-of select="$myVar1/title"/>
    <xsl:value-of select="$myVar2/title"/>

  </xsl:template>
</xsl:stylesheet>

【问题讨论】:

【参考方案1】:

规则在https://www.w3.org/TR/xslt-30/#variable-values给出

快速总结:如果没有select 属性和as 属性,那么变量的值是一个新的文档节点,其中包含作为子元素复制的元素。正是这个额外的级别阻止了路径表达式的工作。对于select="library/book",变量的值是book 元素,对于序列构造函数,该值是一个文档节点,其子节点为book

【讨论】:

【参考方案2】:

我希望 myVar1 和 myVar2 相同

但它们相同:

第一个变量包含对book 节点的引用 源文件。

第二个变量包含book 节点在其自己的文档中副本

因此,指令:

<xsl:value-of select="$myVar2/title"/>

返回空,因为title 不是$myVar2 的子级。 $myVar2 的内容是复制的 book 节点 - 为了获取其子节点 title 的值,您需要使用:

<xsl:value-of select="$myVar2/book/title"/>

【讨论】:

【参考方案3】:

我测试一下。

如果你输入了一个文件,你可以将它包含在&lt;?xe.source [FILE_PATH]&gt;

这是我的名为 Test_XML_1.xml 的 XML 文件:

<?xml version="1.0"?>
<library>
  <book>
    <language>french</language>
    <title>Les Misérables</title>
  </book>
  <book>
    <language>english</language>
    <title>Great Expectations</title>
  </book>
</library>

和你的一样。

这是我的 XSLT 代码:

<?xml version="1.0" encoding="UTF-8"?><?xe.source ../TemporaryFiles/Test_XML_1.xml#library?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output media-type="text/xml" method="xml"></xsl:output>
    <xsl:variable name="myVar1" select="/library/book[language='french']"></xsl:variable>
    <xsl:variable name="myVar2">
        <xsl:copy-of select="/library/book[language='french']"></xsl:copy-of>
    </xsl:variable>
    <xsl:template match="/">
        <root>
            <xsl:copy-of select="$myVar1"></xsl:copy-of>
            <xsl:copy-of select="$myVar2"></xsl:copy-of>
        </root>
    </xsl:template>
</xsl:stylesheet>

使用文件和 XSLT,我得到以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<book>
<language>french</language>
<title>Les Misérables</title>
</book>
<book>
<language>french</language>
<title>Les Misérables</title>
</book>
</root>

要正确使用变量,您需要在 &lt;output&gt;&lt;template&gt; 元素之间声明它们。否则,您需要使用模板调用。就像在每种编程/脚本语言中一样。设置全局或局部变量。

顺便说一句。您需要清楚自己在 XPath 中的位置。

如果你说一次library/book[language='french'],当你切换或退出模板时,你会在这条路径中感到很困惑。您要处理的问题是使用动态 XPath 或静态 XPath。

所以你也可以使用这个解决方案:

<?xml version="1.0" encoding="UTF-8"?><?xe.source ../TemporaryFiles/Test_XML_1.xml#library?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output media-type="text/xml" method="xml"></xsl:output>
    <xsl:template match="/">
        <xsl:variable name="myVar1" select="library/book[language='french']"></xsl:variable>
        <xsl:variable name="myVar2">
            <xsl:copy-of select="library/book[language='french']"></xsl:copy-of>
        </xsl:variable>
        <root>
            <xsl:copy-of select="$myVar1"></xsl:copy-of>
            <xsl:copy-of select="$myVar2"></xsl:copy-of>
        </root>
    </xsl:template>
</xsl:stylesheet>

要将路径的一部分添加到选定的路径,请使用:

&lt;xsl:value-of select="//*[$myVar2]/title" /&gt; 那么应该可以工作了。

我希望这个小任务对你有所帮助;)

【讨论】:

谢谢,但我的目标是使用 myVar2 作为结构化元素。在输出中我不想要整个结构,我想查询$myVar2/title并只显示这个标题 @user14027976 我在我的遮阳篷中添加了一条线。这应该可以解决您的问题;)【参考方案4】:

你可以使用

<xsl:variable name="myVar2" as="element()*">
  <xsl:copy-of select="library/book[language='french']"/>
</xsl:variable>

让您的变量保存一系列元素节点,而不是包含元素节点的文档(片段)节点。

【讨论】:

以上是关于在 XSLT 2.0 中定义变量时使用 xsl:copy-of的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 2.0 按另一个样式表中的变量排序

XSLT 2.0 中的尾递归函数不起作用

XSLT 2.0 产生错误:“上下文项未定义”

XSLT:显示尾随零

XSLT 2.0 的 HTML 请求

XHTML 到 XML XSLT 的转换