XSLT - 使用except除去后代节点

时间:2016-06-23 01:10:46

标签: xml xslt xslt-2.0

假设我有一个这样的示例XML文件,

<Entry>
    <lang>
        <definition>definition</definition>
        <note>aaaaaaaaa
            <list>
                <list-item>aabbbbbbbb</list-item>
                <list-item>aacccccccc</list-item>
                <list-item>aadddddddd</list-item>
            </list>
        </note>
        <example>bbbbbbbbbbb
            <list>
                <list-item>bbaaaaaaa</list-item>
                <list-item>bbbbbbbbbbb</list-item>
                <list-item>bbcccccccc</list-item>
            </list>
        </example>
    </lang>
</Entry>

我已经写过这样的样本xsl,

<xsl:template match="Entry">
        <term>
            <xsl:apply-templates select="node() except definition"/>
        </term>
    </xsl:template>

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

    <xsl:template match="lang">
        <para type="Lang">
            <xsl:apply-templates/>
        </para>
    </xsl:template>

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

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

    <xsl:template match="list-item">
        <para type="list-item">
            <xsl:apply-templates/>
        </para>
    </xsl:template>

正如我在Entry模板中所写的那样,我需要从输出中删除<definition>内容。 (<xsl:apply-templates select="node() except definition"/>)。

据我所知,我可以抑制像<xsl:template match="definition"/>这样的元素并删除内容,但在我的实际场景中我不能使用该方法。似乎except关键字仅适用于给定节点的子元素,但不适用于上述示例的后代元素。

有任何建议如何消除<definition>中apply-template中的xsl:template match="Entry"? (不使用supress definition元素或使用不同的模式)

2 个答案:

答案 0 :(得分:0)

好吧,definitionlang的孩子 - 所以如果你想消除它,你需要在从lang调用模板时这样做:

<xsl:template match="lang">
    <para type="Lang">
        <xsl:apply-templates select="node() except definition"/>
    </para>
</xsl:template>

您现在拥有的模板应用于Entry的所有子节点,definition除外。但由于definition不是Entry的孩子,因此该例外毫无意义。

  

似乎except关键字仅适用于给定节点的子元素   但不是上面例子中的后代元素。

不,except适用于它之前的任何节点集。

加了:

  

但即使我写xsl:apply-templates select="node() except descendant::definition" ... <definition>内容也没有   消除?

当你写:

<xsl:apply-templates select="node()">

这是缩写:

<xsl:apply-templates select="child::node()">

except descendant::definition添加到此是没有意义的。它相当于:

A, B, C except D

如果你写了:

,你会看到不同的结果
<xsl:apply-templates select="descendant::node() except descendant::definition"/>

但这也会改变输出的结构。如果要保留原始层次结构,则必须以递归方式将模板从父级应用于子级 - 正如您所做的那样。

答案 1 :(得分:0)

你明显对处理模式产生了深刻的误解,从你对你所给出的(非常好的)答案的评论来判断。

首先,xsl:apply-templates选择一组节点,并使用最佳匹配模板规则处理每个节点。

因此<apply-templates select="node()"/>将模板应用于表达式node()选择的所有节点,即上下文节点的所有子节点。

现在,什么节点表达式“node()除了定义”选择?答案:除名为“定义”的子节点外的所有子节点。由于没有名为“definition”的子节点,因此它选择与表达式“node()”完全相同的节点。

你试图做的是某种“远距离行动”:你试图说“以正常方式处理这些节点,但是当你这样做时,如果你在任何时候到达节点称为“定义”,然后忽略它“。 XSLT不是这样工作的,也没有任何其他编程语言:你不能改变一些间接调用的函数或模板的效果,除非通过传递它理解的参数。您可以通过传递隧道参数获得最接近的值,但它们只会修改显式编写的模板的效果以查找这些参数。

但这是实现你想要的过于复杂的方式。有两种方法可以确保不处理定义元素:

(a)不要选择它们进行处理。您选择要进行处理的地方来自带有match =“lang”的模板,这就是您需要更改的内容。

(b)确保如果选择它们进行处理,则处理不产生输出,这意味着更改definition元素的模板规则。