0

我需要为下面的输入使用 XSLT。此转换的目的是识别特定项目是否已被删除或重新创建

这是输入示例: 第一个场景:

<root> 
    <nodeA id="a">
        <object id="1">
            <item1 id="xx" method="create">
                <attr>
                    <color>yellow</color>
                </attr>
            </item1>
        </object>
        <object id="1">
            <item1 id="xx" method="change">
                <any>blah</any>
                <attr>
                    <color>green</color>
                </attr>
            </item1>
            <item1 id="xx" method="delete" />                
        </object>  
        <object id="2">
            <item1 id="yy" method="create">
               <any>aaa</any>
            </item1>
        </object>
    </nodeA>            
</root>

输出:

<root> 
    <nodeA id="a">
        <object id="1">            
        </object>
        <object id="1">           
            <item1 id="xx" method="delete" />                
        </object>  
        <object id="2">
            <item1 id="yy" method="create">
               <any>aaa</any>
            </item1>
        </object>
    </nodeA>            
</root>

在上面的第一个场景中,我们看到 item1 已经被创建,更改然后删除,这意味着它最终会被删除,这就是为什么我们只保留<item1 id="xx" method="delete" />和忽略另一个。

第二种情况:

<root> 
    <nodeB id="a">
        <object id="2">
            <item2 id="xx" method="create">
                <attr>
                    <color>yellow</color>
                </attr>
            </item2>
        </object>
        <object id="2">
            <item2 id="xx" method="change">
                <attr>
                    <color>green</color>
                </attr>
            </item2>
            <item2 id="xx" method="delete" /> <!-- because deletion occurs here, we disregard any previous node up until this delete -->
            <item2 id="xx" method="create"> <!-- we keep this node and any node afterwards -->
                <attr>
                    <color>pink</color>
                </attr>
            </item2>
            <item2 id="xx" method="change">
                <any>blah</any>
                <attr>
                    <color>red</color>
                </attr>
            </item2>
        </object>  
        <object id="3">
            <item2 id="yy" method="create">
                <any>ccc</any>
            </item2>
        </object>
    </nodeB>            
</root>

输出:

<root> 
    <nodeB id="a">
        <object id="2">            
        </object>
        <object id="2">            
            <item2 id="xx" method="create"> 
                <attr>
                    <color>pink</color>
                </attr>
            </item2>
            <item2 id="xx" method="change">
                <any>blah</any>
                <attr>
                    <color>red</color>
                </attr>
            </item2>
        </object>  
        <object id="3">
            <item2 id="yy" method="create">
                <any>ccc</any>
            </item2>
        </object>
    </nodeB>            
</root>

在第二种情况下:我们看到 item2 在创建和更改后被删除,然后重新创建和/或重新更改。这就是为什么我们在删除之前忽略所有节点,然后只保留所有节点。

所以总而言之:

  • create/change/.../delete -> 将变为删除

  • 创建/更改/.../删除/create2/change2/... -> create2/change2/...

任何帮助将不胜感激。谢谢。

约翰

4

1 回答 1

2

我认为在 XSLT 中编码有两条规则

  • 如果您有一个带有“删除”方法的项目,那么只有在没有相同@id(和父@id)的后续项目时才输出它

  • 如果您有一个项目的方法不是“删除”,那么只有在没有相同@id(和父@id)的后续“删除”项目时才输出

第一条规则可以这样编码

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

第二条规则是这样的

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

注意我通过查找没有任何具有@id 属性的子元素的元素来识别“项目”节点(即item1item2 )。另请注意,在这两种情况下,我假设这只发生在当前nodeA/B元素中。

这是完整的 XSLT

<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:call-template name="identity" />
        </xsl:if>
    </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:call-template name="identity" />
        </xsl:if>
    </xsl:template>    

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

当应用于您的第一个 XML 示例时,输出如下

<root>
    <nodeA id="a">
        <object id="1"/>
        <object id="1">
            <item1 id="xx" method="delete"/>
        </object>
        <object id="2">
            <item1 id="yy" method="create">
                <any>aaa</any>
            </item1>
        </object>
    </nodeA>
</root>

当应用于您的第二个 XML 示例(不带注释)时,输出如下

<root>
    <nodeB id="a">
        <object id="2"/>
        <object id="2">
            <item2 id="xx" method="create">
                <attr>
                    <color>pink</color>
                </attr>
            </item2>
            <item2 id="xx" method="change">
                <any>blah</any>
                <attr>
                    <color>red</color>
                </attr>
            </item2>
        </object>
        <object id="3">
            <item2 id="yy" method="create">
                <any>ccc</any>
            </item2>
        </object>
    </nodeB>
</root>
于 2012-05-20T10:29:51.880 回答