XSLT:参数化节点上的递归模板

XSLT: recursive templates on parametrized nodes

我试图在节点类型的参数化列表上递归调用模板。

如果我将这些参数化值传递给模板,它不会递归。 但是,如果我直接将值传递给模板,递归会按预期工作。

如何在匹配参数化值时使递归起作用?

(我正在使用 saxon 版本 9.9.1.6(家庭版)来应用 XSLT 转换)

输入HTML

<p>
<p>paragraph1</p>
<p>paragraph2</p>
<a>link here</a>
</p>

具有模板直接值的 XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="container" select="p|a"/>    
<xsl:template match="p|a">
    Name: <xsl:value-of select="name()"/>
    Value: <xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="UTF-8"?>
    Name: p
    Value: 

    Name: p
    Value: paragraph1

    Name: p
    Value: paragraph2

    Name: a
    Value: link here

这是有效的,也是我期望发生的事情。 但是当我尝试将参数化值传递给模板时,它匹配顶级元素但不匹配任何子元素。

具有模板参数化值的 XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="container" select="p|a"/>    
<xsl:template match="$container">
    Name: <xsl:value-of select="name()"/>
    Value: <xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="UTF-8"?>
    Name: p
    Value: 
paragraph1
paragraph2
link here

match="$variable" 是 XSLT 3.0 中的新语法,它匹配全局变量中保存的节点集中的节点。该变量包含匹配的节点,而不是它们的名称。

此外,select="p|a" selects 节点在文档的上下文中,这不是您想要的。使用 select="'p|a'" 将变量设置为字符串。它有助于使用 as 属性,例如。 as="node()*"as="xs:string" 以避免混淆变量实际应该包含的内容。

要匹配姓名,请使用 match="*[local-name()=tokenize($container, '\|')]"

或者您可以定义静态参数和影子属性:

<xsl:param name="container" select="'p|a'" static="yes"/>

<xsl:template _match="{$container}">...</xsl:template>

或者,如果您愿意,可以将变量初始化为匹配节点集,如下所示:

<xsl:param name="matching-nodes" select="//p | //a"/>

然后使用

匹配
<xsl:template match="$matching-nodes"/>

但请注意,这仅在您匹配主要源文档中的节点时有效。

编辑:我没有看到 Kay 博士的回答,所以把这当作他的扩展。


结果是预期的。来自 https://www.w3.org/TR/2017/REC-xslt-30-20170608/#patterns

  • $xyz matches any node that is present in the value of the variable $xyz.

来自https://www.w3.org/TR/2017/REC-xslt-30-20170608/#dt-global-variable

For a global variable or the default value of a stylesheet parameter, the expression or sequence constructor specifying the variable value is evaluated with a singleton focus as follows:

  • If the declaration appears within the top-level package (including within an xsl:override element in the top-level package), then the
    focus is based on the global context item if supplied, or absent
    otherwise.
  • If the declaration appears within a library package, then the focus is absent.

当前规范很好地警告了全局上下文项(全局变量声明的上下文)和初始匹配选择(要处理的第一个项目)之间的可能差异,但这让您有需要在您的 XSLT 处理器自己的文档中查看默认设置是什么...

我将假定情况表述为specs中的注释:

Note:

In previous releases of this specification, a single node was typically supplied to represent the source document for the transformation. This node was used as the target node for the implicit call on xsl:apply-templates used to start the transformation process (now called the initial match selection), and the root node of the containing tree was used as the context item for evaluation of global variables (now called the global context item).[...]

Built-in Template Rules 相结合产生以下工作流程:

  1. 变量$container设置在文档节点的上下文中 或根:表达式选择 p 文档元素。
  2. 文档节点或根由内置规则匹配。申请 儿童模板。
  3. 文档元素 p 与您的模板匹配。输出你的 内容模板并将模板应用于子项。
  4. p 文档元素的每五个子元素都由内置匹配 规则:输出两个只有空格的文本节点,三个元素是 绕过。
  5. 三个文本节点paragraph1paragraph2link here是 输出。