在XSLT中省略输入部分,但匹配除外

时间:2016-06-06 15:34:30

标签: xml xslt transformation

我现在可以看到,我对XSL很陌生。

假设我输入了

<?xml version="1.0" encoding="UTF-8"?>
<Doc>
<A>A</A>
<B>B</B>
<C>C</C>
</Doc>

并将其传递给XSLT,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="A">
    <xsl:element name="Info">This is an <xsl:value-of select="."/></xsl:element>
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

我会得到

<?xml version="1.0" encoding="UTF-8"?>
<Info>This is an A</Info>A
B
C

我怎样才能摆脱这些额外的A和其他B&C假设有一些复杂的树,我怎么能说只转换我模板中匹配的元素,省略其他所有?

最诚挚的问候和提前谢谢

2 个答案:

答案 0 :(得分:1)

这是因为XSLT的built-in template rules

有多种方法可以覆盖内置规则,例如添加与text()匹配的空xsl:模板。

在您的特定情况下,我可能会在模板中添加一个选择xsl:apply-templates以匹配根元素(/*)并从匹配的模板中删除xsl:apply-templates A ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/*">
    <xsl:apply-templates select="A"/>
</xsl:template>

<xsl:template match="A">
    <xsl:element name="Info">This is an <xsl:value-of select="."/></xsl:element>
</xsl:template>

</xsl:stylesheet>

另请注意,如果您要创建新元素,则除非您动态创建名称,否则 不能使用xsl:element。只是输出它......

<Info>This is an <xsl:value-of select="."/></Info>

答案 1 :(得分:0)

您看到的附加输出是XSLT内置标准规则的效果。

这些说:“通过输入树递归并处理每个节点。对于元素节点,处理它们的子节点,对于文本节点,将它们的内容复制到输出。”

另请参阅more in-depth explanation #1more in-depth explanation #2,当然还有the spec

每当没有处理特定节点的规则(即模板)时,这些标准规则就会生效。

这就是这里发生的事情:

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

它读取:“匹配根节点和进程(即应用​​模板)任何子元素。”

这将处理根节点,并继续处理根节点的唯一子节点 - 文档元素<Doc>。之后,处理器继续处理子项。 <A>有一个自定义模板,<B><C>没有自定义模板,这意味着将使用默认规则,其文本内容将以输出结束。

请注意,这也意味着上述模板是一个可以安全地完全丢弃的无操作模式,而不会对结果进行任何更改。它只是重新迭代默认规则会做什么。

出路:

  • 制作一个与<B><C>匹配的自定义模板,不会产生任何输出:

    <xsl:template match="B | C" />
    
  • 创建一个与任何元素节点匹配的自定义模板,并且不生成任何输出:

    <xsl:template match="*" />
    

    这是因为匹配表达特异性。更具体的匹配表达式将优先于不太具体的匹配表达式,因此即使match="*"也匹配<A>,也会优先使用match="A"的模板。

  • 首先不要在已处理的节点中包含<B><C>

    <xsl:template match="/*">
        <xsl:apply-templates select="A" />
    </xsl:template>
    

    请注意,match="/"与根节点匹配,而match="/*"与文档元素匹配(如上所述,存在差异)。您可以使用match="/Doc",这比/*更具体。但是,/*是表达“文档元素,无论它可能被称为”的常见约定。

这三种策略都是有效的,这取决于您想要使用的情况和您的偏好。