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>

アイデアは、要素ノードとの組み合わせを削除したいということです

  • 1 つのメソッド create の後に1 つまたは複数の変更が続き、その後に1 つのdelete メソッドが続き、残りはそのままにしておきます。
  • たとえば、同じ要素名である必要があり<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

ジョン、私はあなたが好きかもしれないし嫌いかもしれない解決策を持っています. 物事を少し単純化するために、1 つの「最適化」を行いました。sectionこれらのノードを同じものと同じ@idように扱っているので、結果ドキュメントでそれらがすべて 1 つにマージされているのを見ても気にしないかもしれないと考えました。これが受け入れられるかどうかを確認してください。

次の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ましchangeた。それらはすべて「知られている」deletechangecreatedeletedeletechangecreatename()@idname()と同じ ( and ) 親から来ている@idので、その部分をチェックする必要はありません。

于 2012-06-01T01:36:40.273 に答える