XSLT:如何从父节点复制元素并在之后删除它们

时间:2015-09-28 21:43:00

标签: xml xslt

我有以下XML:

<entry>
<form type="variant">
    <form type="hyperlemma">
        <orth>wordA</orth>
    </form>
    <orth>wordB</orth>
    <gramGrp>
        <gram>vb</gram>
        <gram>inf</gram>
    </gramGrp>
    <cit>
        <form type="lemma">
            <orth>wordC</orth>
        </form>
    </cit>
    <form type="graphical_variant">
        <form type="hyperlemma">
            <orth>wordD</orth>
        </form>
        <orth>wordE</orth>
        <cit>
            <orth>∅</orth>
        </cit>
    </form> 
</form>
</entry>

<form type="variant">的子节点 - 即<orth>wordB</orth><cit> - 应该在第一个<form type="graphical_variant">之前新添加。{/ p >

所需的输出是

<entry>
<form type="variant">
    <form type="hyperlemma">
        <orth>wordA</orth>
    </form>
    <gramGrp>
        <gram>vb</gram>
        <gram>inf</gram>
    </gramGrp>
    <form type="graphical_variant">
        <orth>wordB</orth>
        <cit>
        <form type="lemma">
            <orth>wordC</orth>
        </form>
    </cit>
    </form>
    <form type="graphical_variant">
        <form type="hyperlemma">
            <orth>wordD</orth>
        </form>
        <orth>wordE</orth>
        <cit>
            <orth>∅</orth>
        </cit>
    </form> 
</form>
</entry>

应用此XSLT,模板1和2正在进行复制

<!--TEMPLATE1-->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
</xsl:template>
<!--TEMPLATE2-->
<xsl:template match="form[@type='graphical_variant']">
    <form type="graphical_variant">
        <xsl:apply-templates select="../orth" />
        <!--in case there are several <cit> elements-->
        <xsl:for-each select="../cit">
            <xsl:apply-templates select="." />
        </xsl:for-each>
    </form>
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>
<!--TEMPLATE3-->
<xsl:template match="form[@type='variant']/cit" />
<!--TEMPLATE4-->
<xsl:template match="form[@type='variant']/orth"/>

但是一旦我尝试使用模板3和4从<form type="variant">删除这些复制的元素,它们也会从新创建的元素<form type="graphical_variant">中删除。

这可能是一个愚蠢的问题,但为什么会这样呢?通过引用form[@type='variant'](template3),我认为<cit>只会被删除。如果有人能解释我做错了什么,我会很高兴 - 甚至可能提供解决方案!

我忘了提到:它是XSLT 2.0。

2 个答案:

答案 0 :(得分:2)

您的方法存在问题:当您这样做时:

<xsl:apply-templates select="../orth" />

您正在将模板应用于作为当前节点的兄弟节点的orth元素 - 即<form type="variant">元素的子元素。只有匹配这些orth元素的模板 - 它是您的TEMPLATE4,并且该模板为空。

同样的事情发生在你的:

<xsl:for-each select="../cit">
    <xsl:apply-templates select="." />
</xsl:for-each>

这只是一种尴尬的说法:

<xsl:apply-templates select="../cit" />

将空TEMPLATE3应用于这些节点。

如何解决此问题:

有三种方法可以解决这个问题:

  1. 而不是应用模板,复制节点到您想要的位置     它们:

    <!--TEMPLATE1--> 
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy> 
    </xsl:template>
    <!--TEMPLATE2--> 
    <xsl:template match="form[@type='graphical_variant']">
        <form type="graphical_variant">
            <xsl:copy-of select="../orth" />
            <xsl:copy-of select="../cit" />
        </form>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy> 
    </xsl:template>
    <!--TEMPLATE3--> 
    <xsl:template match="form[@type='variant']/cit" />
    <!--TEMPLATE4--> 
    <xsl:template match="form[@type='variant']/orth"/>
    
  2. 如果要复制节点,请应用不同的模板(使用模式)。

  3. 在应用模板时更具选择性(这,恕我直言,是 优选的方法):

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="form[@type='variant']">
        <xsl:copy>
            <!-- remove orth and cit from here -->
            <xsl:apply-templates select="@*|node() except (orth|cit)"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="form[@type='graphical_variant']">
        <form type="graphical_variant">
            <!-- add orth and cit here -->
            <xsl:apply-templates select="../orth" />
            <xsl:apply-templates select="../cit" />
        </form>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

答案 1 :(得分:0)

<xsl:apply-templates select="." />

在这里,它匹配示例底部的空模板。

简单但不是最佳解决方案

<xsl:apply-templates select="." mode="noignore" />

然后使用mode =&#34; noignore&#34;制作符合您所需元素的内容。并实际上复制它们而不是抑制。