0

我有这个输入:

<root>
    <sector>
        <nodeA id="a">
            <section id="i">
                <item1 id="1" method="delete"/>

                <item1 id="1" method="create"> 
                    <somechild>a</somechild>
                </item1>
                <item1 id="1" method="change"> 
                    <somechild>a</somechild>
                </item1>
            </section>
            <section id="i">
                <item1 id="1" method="change"> 
                    <somechild>a</somechild>
                </item1>
            </section>
            <section id="i">
                <item1 id="1" method="delete"/>
                <item1 id="1" method="create">
                    <somechild>a</somechild>
                </item1>
            </section>
        </nodeA>
    </sector> 
</root>

我的 XSL 是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="*[not(.//*[@id!=''])][@method='delete']">
        <xsl:if test="not(following::*[not(.//*[@id!=''])][@id=current()/@id][../@id = current()/../@id][generate-id(../..) = generate-id(current()/../..)])"/>       
    </xsl:template>    

    <xsl:template match="*[not(.//*[@id!=''])][@method!='delete']">
        <xsl:if test="not(following::*[not(.//*[@id!=''])][@method='delete'][@id=current()/@id][../@id = current()/../@id][generate-id(../..) = generate-id(current()/../..)])"/>
    </xsl:template>    

    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

我的输出:

<root>
    <sector>
        <nodeA id="a">
            <section id="i">
            </section>
            <section id="i">
            </section>
            <section id="i">
            </section>
        </nodeA>
    </sector>
</root>

预期输出:

<root>
    <sector>
        <nodeA id="a">
            <section id="i">
                <item1 id="1" method="delete"/> <!-- leave this node -->
            </section>
            <section id="i">
            </section>
            <section id="i">
                <item1 id="1" method="create"> <!-- leave this node -->
                    <somechild>a</somechild>
                </item1>
            </section>
        </nodeA>
    </sector> 
</root>

这个想法是我想删除元素节点的组合

  • 一种方法创建,然后是一种或多种修改,然后是一种删除方法,其余的保持不变。
  • 例如,它必须是相同的元素名称,<item1>并且@id在相同的父级下<section id=1>

任何人都可以帮助我进行转型吗?

谢谢。约翰

4

2 回答 2

1

好吧,这并不容易,但它适用于 xslt 1.0!

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
<!--
    copies all nodes with id
    if there first preceding delete followed by the first preceding create
    -->
    <xsl:template match="*[not(.//*[@id!=''])]">
        <xsl:variable name="id" select="@id"/>
        <xsl:variable name="parentId" select="../@id"/>
        <xsl:variable name="precedings" select="preceding::*[@id=$id][../@id=$parentId]"/>
        <xsl:variable name="lastDelete" select="($precedings[@method='delete'])[last()]"/>
        <xsl:variable name="lastCreate" select="($precedings[@method='create'])[last()]"/>
        <xsl:variable name="openCreate" select="$lastDelete[following::* = $lastCreate] or (not($lastDelete) and $lastCreate)"/>
        <xsl:if test="not(following::*[@id=$id][../@id=$parentId][@method='delete'] and $openCreate)">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

    <!--
    copies all deletes, if they have no preceding creates
    -->
    <xsl:template match="*[not(.//*[@id!=''])][@method='delete']" priority="10">
        <xsl:variable name="id" select="@id"/>
        <xsl:variable name="parentId" select="../@id"/>
        <xsl:variable name="precedings" select="preceding::*[@id=$id][../@id=$parentId]"/>
        <xsl:variable name="precCreate" select="$precedings[@method='create']"/>
        <xsl:if test="not($precCreate)">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

<!--
    copies all creates, if they have no following deletes
    -->

    <xsl:template match="*[not(.//*[@id!=''])][@method='create']" priority="10">
        <xsl:variable name="id" select="@id"/>
        <xsl:variable name="parentId" select="../@id"/>
        <xsl:variable name="followings" select="following::*[@id=$id][../@id=$parentId]"/>
        <xsl:variable name="followDelete" select="$followings[@method='delete']"/>
        <xsl:if test="not($followDelete)">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>

    <!--
        copies all nodes
    -->
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

测试它...没有保证!

于 2012-06-01T08:53:54.670 回答
1

约翰,我有一个你可能喜欢也可能不喜欢的解决方案。我做了一个“优化”来简化一些事情。我认为,由于您将这些section节点@id视为相同的相同,您可能不介意在结果文档中看到它们全部合并为一个。看看这是否可以接受。

以下XSLT 2.0转换:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="nodeA">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each-group select="*" group-by="concat(name(), '|', @id)">
                <xsl:copy>
                    <xsl:apply-templates select="@*"/>
                    <xsl:variable name="merged">
                        <xsl:for-each-group select="current-group()/*"
                                            group-by="concat(name(), '|', @id)">
                            <xsl:copy-of select="current-group()"/>
                        </xsl:for-each-group>
                    </xsl:variable>
                    <xsl:apply-templates select="$merged/*"/>
                </xsl:copy>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[@method = 'create']
                          [following-sibling::*[@method = 'change']
                                               [following-sibling::*[@method = 'delete']]]"/>
    <xsl:template match="*[@method = 'change']
                          [preceding-sibling::*[@method = 'create']]
                          [following-sibling::*[@method = 'delete']]"/>

    <xsl:template match="*[@method = 'delete']
                          [preceding-sibling::*[@method = 'change']
                                               [preceding-sibling::*[@method = 'create']]]"/>

</xsl:stylesheet>

当应用于您的输入文档时会产生:

<root>
    <sector>
      <nodeA id="a">
         <section id="i">
            <item1 id="1" method="delete"/>
            <item1 id="1" method="create">
                    <somechild>a</somechild>
                </item1>
         </section>
      </nodeA>
    </sector>
</root>

我认为将这些item1节点折叠成一个扁平的有序列表会更容易,然后才过滤掉你想要删除的序列。我必须将它们复制到一个变量中以从原始文档树中“分离”,否则这些sibling轴将在原始父节点中查找。一旦你有一个来自“相同”父节点的“相同”节点的平面列表item1,过滤创建-更改-删除序列真的是小菜一碟。我刚刚将您的规则直接翻译成 XPath 谓词 - 一个表示create后跟changea delete,另一个表示changebeforecreate和后跟 a delete,最后一个表示deletebeforeed changeby create。他们都是“已知的”name()@id并且来自同一个 (name()@id) 父级,因此我们不必检查该部分。

于 2012-06-01T01:36:40.273 回答