0

この入力ファイルが xml にある場合:

<root> 
    <node id="N1">
        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <year>2000</year>
                </attribute>
            </orange>                        
        </fruit>        

        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <condition>good</condition>
                </attribute>
            </orange>                        
        </fruit>        
    </node>
</root>

期待される出力は次のとおりです。

<root> 
    <node id="N1">
        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <year>2000</year>
                    <condition>good</condition>
                </attribute>
            </orange>                        
        </fruit>        

        <fruit id="1">                                 
        </fruit>
    </node>
</root>

2 つの兄弟間を簡略化する方法:

  1. 親が同じかどうかを確認します (フルーツ id=1)
  2. ノード ID とアクションが同じかどうかを確認します (orange id=x action=create)
  3. 子要素が既に定義されていて、値が同じ (オレンジ色) の場合、それを削除します。
  4. 2 番目の兄弟の子要素が以前に定義されていない場合、その 2 番目のノードを最初のノードに追加します。(状態良好)
  5. ノードがすでに定義済みであるが値が異なる場合 (color-red など)、ノードをそのままにします。

別のシナリオ: input2:

<root> 
    <node id="N1">
        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>                   
                </attribute>
            </orange>                        
        </fruit>        

        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Red</color>
                    <condition>good</condition>
                </attribute>
            </orange>                        
        </fruit>        
    </node>
</root>

予想される出力:

<root> 
    <node id="N1">
        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <condition>good</condition>
                </attribute>
            </orange>                        
        </fruit>        

        <fruit id="1">
            <orange id="x" action="create">
                <attribute>
                    <color>Red</color>
                </attribute>
            </orange>                        
        </fruit>        
    </node>
</root>

別のシナリオ:

<root> 
    <nodeA id="A">
        <fruit id="1">
            <orange id="x" action="delete" />    <!-- no attributes here -->                                         
        </fruit>        

        <fruit id="1">
            <orange id="x" action="delete"/>   
            <orange id="y" action="delete" />                                            
        </fruit>        
    </nodeA>
</root>

期待される出力:

<root> 
    <nodeA id="A">
        <fruit id="1">
            <orange id="x" action="delete" />   
        </fruit>        

        <fruit id="1"> 
            <orange id="y" action="delete" />                                         
        </fruit>        
    </nodeA>
</root>

この例で明確なアイデアが得られることを願っています。変換ファイルを手伝ってください。ありがとう。

ジョン

4

1 に答える 1

2

ジョン、これは機能するバージョンです。これはやや残忍で手続き的なので、本当に XSLT でこの種のロジックを実行したいのだろうかと思います。どうぞ:

次のスタイルシート:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="entity" match="node/*/*" use="concat(parent::*/@id, '_', @id, '_', @action)"/>

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

    <xsl:template match="node/*/*[not(attribute)][generate-id() != generate-id(key('entity', concat(parent::*/@id, '_', @id, '_', @action))[1])]"/>

    <xsl:template match="node/*/*[attribute]">
        <xsl:variable name="attributes">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()">
                    <xsl:with-param 
                            name="mode" 
                            select="generate-id() = generate-id(key('entity', concat(../@id, '_', @id, '_', @action))[1])"/>
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:variable>
        <xsl:if test="$attributes/*/attribute/*">
            <xsl:copy-of select="$attributes"/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="node/*/*/attribute">
        <xsl:param name="mode"/>
        <xsl:variable name="all-attributes" select="key('entity', concat(../../@id, '_', ../@id, '_', ../@action))/attribute/*"/>
        <xsl:copy>
            <xsl:if test="$mode = true()">
                <xsl:for-each-group select="$all-attributes" group-by="local-name()">
                    <xsl:copy>
                        <xsl:apply-templates select="@* | node()"/>
                    </xsl:copy>
                </xsl:for-each-group>
            </xsl:if>
            <xsl:if test="$mode = false()">
                <xsl:for-each select="*">
                    <xsl:variable 
                        name="same-name-attr" 
                        select="$all-attributes[local-name() = current()/local-name()][count(. | current()/preceding::*) = count(current()/preceding::*)]"/>
                    <xsl:if test="$same-name-attr and not(. = $same-name-attr)">
                        <xsl:copy-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:if>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

次の結果が生成されます

<root>
   <node id="N1">
      <fruit id="1">
         <orange id="x" action="create">
            <attribute>
               <color>Orange</color>
               <year>2000</year>
               <condition>good</condition>
               <new>!!</new>
            </attribute>
         </orange>
      </fruit>
      <fruit id="1">
         <orange id="x" action="create">
            <attribute>
               <color>Red</color>
            </attribute>
         </orange>
      </fruit>
      <fruit id="1">
         <orange id="x" action="create">
            <attribute>
               <color>Blue</color>
            </attribute>
         </orange>
      </fruit>
      <fruit id="1">
         <orange id="x" action="create">
            <attribute>
               <condition>ugly</condition>
            </attribute>
         </orange>
      </fruit>
      <fruit id="1"/>
   </node>
</root>

すべての一意の属性は、createアクションの最初の発生時にプルアップされ、異なる値の属性を持つ属性のみがfollowing::ノードに残ります。ノードに追加する新しいものがない場合、取り残されます。次のオカレンスのために属性を保持する価値があるかどうかを判断する方法は次のとおりです。属性が以前に見られなかった場合、それはすでに最初のオカレンスにプルアップされているため、スキップします。以前に表示されたことがあり (=preceding軸上の同じ名前の属性のコレクションにある)、異なるテキスト値を持っている場合にのみ、それを保持します。

やりたいことのセレクターは次第に複雑になっているので、一時変数を使用して基本的にテンプレートにそれを試してもらい、結果があるかどうかを調べて、結果ツリーにコピーする価値があるかどうかを判断する必要がありました。このロジックを一致述語に変換する方法があるかもしれませんが、より読みやすくなるかどうかはわかりません。それが理にかなっていることを願っています。

更新属性のないコーナーケースでも機能するようにソリューションを更新しました。私は基本的に、反復的な no-node を黙らせattribute、メイン テンプレートを s を持つノードでのみ機能するようにもう少し具体的にする必要がありましたattribute。属性を持つノードを「繰り返す」属性のないノードは、主要な属性マージ ロジックを使用してサイレントになります。残すattribute必要のある no-s ノードは、デフォルトの恒等変換を使用してコピーされます。

于 2012-05-03T20:13:20.687 に答える