【问题标题】:xsl:variable xsl:copy-of selectxsl: 变量 xsl: 复制选择
【发布时间】:2012-12-13 17:01:53
【问题描述】:

我有以下 XML:

<?xml version="1.0" encoding="UTF-8"?>
<XmlTest>
    <Pictures attr="Pic1">Picture 1</Pictures>
    <Pictures attr="Pic2">Picture 2</Pictures>
    <Pictures attr="Pic3">Picture 3</Pictures>
</XmlTest>

虽然此 XSL 执行预期的操作(输出第一张图片的属性):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/XmlTest">
        <xsl:variable name="FirstPicture" select="Pictures[1]">
        </xsl:variable>
        <xsl:value-of select="$FirstPicture/@attr"/>
    </xsl:template>
</xsl:stylesheet>

似乎不可能在使用 xsl:copy-of: 的变量声明中做同样的事情:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:template match="/XmlTest">
        <xsl:variable name="FirstPicture">
            <xsl:copy-of select="Pictures[1]"/>
        </xsl:variable>
        <xsl:value-of select="$FirstPicture/@attr"/>
    </xsl:template>
</xsl:stylesheet>

好奇: 如果我在第二个示例中只选择“$FirstPicture”而不是“$FirstPicture/@attr”,它会按预期输出图片1的文本节点...

在你们都建议我重写代码之前: 这只是一个简化的测试,我的真正目的是使用命名模板将一个节点选择到变量 FirstPicture 中,并将其重用于进一步的选择。

我希望有人可以帮助我理解这种行为,或者可以建议我一种正确的方法来选择一个具有易于重用的代码的节点(在我的实际应用程序中,决定哪个节点是第一个节点很复杂)。谢谢。

编辑(感谢 Martin Honnen): 这是我的工作解决方案示例(它另外使用单独的模板来选择请求的图片节点),使用 MS XSLT 处理器:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    version="1.0">
    <xsl:template match="/XmlTest">
        <xsl:variable name="FirstPictureResultTreeFragment">
            <xsl:call-template name="SelectFirstPicture">
                <xsl:with-param name="Pictures" select="Pictures" />
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="FirstPicture" select="msxsl:node-set($FirstPictureResultTreeFragment)/*"/>
        <xsl:value-of select="$FirstPicture/@attr"/>
        <!-- further operations on the $FirstPicture node -->
    </xsl:template>

    <xsl:template name="SelectFirstPicture">
        <xsl:param name="Pictures"/>
        <xsl:copy-of select="$Pictures[1]"/>
    </xsl:template>
</xsl:stylesheet>

不好,在 XSLT 1.0 中不能直接从模板输出节点,但使用额外的变量至少不是不可能的。

【问题讨论】:

  • 为什么要执行复制子树的昂贵操作?副本中的属性将与原始属性相同。只需使用选择表单 - 效率更高。并且您避免了与结果树片段相关的 XSLT 1.0 限制。
  • 处理我的例子,你是绝对正确的,选择完整的节点集将是开销。在我的实际应用程序中,我不只是想选择单个属性,而是需要在该节点上提交进一步的操作,例如选择子节点和调用其他模板。我想在我的 xsl 中的几个地方使用它而不复制任何代码。

标签: xslt


【解决方案1】:

如果你愿意,可以使用 XSLT 1.0 处理器

    <xsl:variable name="FirstPicture">
        <xsl:copy-of select="Pictures[1]"/>
    </xsl:variable>

该变量是一个结果树片段,在纯 XSLT 1.0 中您可以使用它输出它并使用copy-of(或value-of)。如果要应用 XPath,首先需要将结果树片段转换为节点集,大多数 XSLT 1.0 处理器都支持扩展功能,因此请尝试

    <xsl:variable name="FirstPictureRtf">
        <xsl:copy-of select="Pictures[1]"/>
    </xsl:variable>
    <xsl:variable name="FirstPicture" select="exsl:node-set(FirstPictureRtf)/Pictures/@attr">

您在样式表中定义xmlns:exsl="http://exslt.org/common" 的位置。

请注意,您需要检查您的 XSLT 1.0 处理器是否支持 EXSLT 扩展功能或另一个命名空间中的类似功能(例如各种 MSXML 版本)。

【讨论】:

  • 你是对的,尽管 VS 调试器窗口将变量显示为 NodeSet 类型,但复制返回结果树片段是正确的:-( 我必须按照您的建议引入第二个变量,它将转换为节点集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
  • 1970-01-01
相关资源
最近更新 更多