3

こんにちは、次の XML を解析するのに助けが必要です。

<xmeml>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
    </Test>
    <Test>
        <Unit>bcd</Unit>
        <Unit2>2345</Unit2>
    </Test>
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>3456</Unit2>
    </Test>
    <Test>
        <Unit>cde</Unit>
        <Unit2>3456</Unit2>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
    </Test>
    <Test>
        <Unit>def</Unit>
        <Unit2>4567</Unit2>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
    </Test>
    <Test>
        <Unit>efg</Unit>
        <Unit2>2345</Unit2>
    </Test> 
</Doc>
</xmeml>

次で終わる

<xmeml>
<Doc>
    <Test>
        <Unit>bcd</Unit>
        <Unit2>2345</Unit2>
    </Test>
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>3456</Unit2>
    </Test>
    <Test>
        <Unit>cde</Unit>
        <Unit2>3456</Unit2>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>def</Unit>
        <Unit2>4567</Unit2>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
    </Test>
    <Test>
        <Unit>efg</Unit>
        <Unit2>2345</Unit2>
    </Test> 
</Doc>
</xmeml>

これを行うために XSLT ドキュメントを作成しようとしていますが、まだ機能するものを見つけていません。「Doc」内で必要な一致パラメーターは、この場合は「abc」と「1234」であることに注意してください。現実の世界では、これらは変数であり、静的な検索可能なエンティティになることはありません。

したがって、英語では、私の XSL は次のようになります。一致する 'Unit' と 'unit2' の値の両方を含む親については、最後を除いて 'Unit' と 'Unit2' の重複値を含むすべての先行する親 'Test' を削除します。

すべての助けに最も感謝します ありがとう

4

3 に答える 3

2

これは比較的簡単な方法ですが、Meunchian 法を使用したより効率的な方法があると確信しています。ただし、パフォーマンスが問題にならない場合は、おそらくこれに従う方が簡単です。

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

  <xsl:template match="Test">
    <xsl:variable name="vUnit" select="Unit" />
    <xsl:variable name="vUnit2" select="Unit2" />
    <xsl:if test="not(following::Test[Unit = $vUnit and Unit2 = $vUnit2])">
      <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>

テンプレートは、とに同じ値を持つTest後の要素があるかどうかを単純にチェックし、ない場合は通常どおり出力します。TestUnitUnit2

于 2012-07-21T08:12:58.010 に答える
1

XSLT 2.0では、for-each-group構造を使用して、重複の排除に関連する多くの問題に取り組むことができます。この場合、for-each-groupを使用した解決策は明らかではありません。これは、実際にはグループ化の問題ではないためです(グループ化の問題では、通常、入力の要素のグループに対応する1つの要素を出力に生成します。ここではそうではありません。)Dimitreと同じ方法で取り組みます。for-each-groupを使用してグループを識別します。したがって、保持する必要のあるテスト要素と削除する必要のあるテスト要素を識別します。実際、私はこれを解決し始め、最後のテンプレートルールを次のように簡略化できることを除いて、Dimitreのものと非常によく似た解決策を思いつきました。

<xsl:template match="Test[not(. intersect $vLastInGroup)]"/>

これは、特定の特性を持つすべての要素を含むノードセット値のグローバル変数を設定し、グローバルノードセットのメンバーシップをテストするテンプレートルールを使用する場合に使用するコーディングパターンの例です(述語を使用[. intersect $node-set]) 。このパターンに従い、XSLT 3.0で利用可能ないくつかの新しい構文を使用して、次のようなコードを作成する傾向があります。

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:mode on-no-match="shallow-copy"/>

 <xsl:variable name="deletedElements" as="element()*">
  <xsl:for-each-group select="/*/Doc/Test"
                      group-by="Unit, Unit2" composite="yes">
   <xsl:sequence select="current-group()[position() ne last()]"/>
  </xsl:for-each-group>
 </xsl:variable>

 <xsl:template match="$deletedElements"/>
</xsl:stylesheet>
于 2012-07-22T09:20:46.187 に答える
0

I. XSLT 1.0 ソリューション:

これは、最も効率的な既知の XSLT 1.0 グループ化方法であるMuenchian グループ化の単純な (変数なしxsl:if、軸なし、軸なしxsl:call-template) アプリケーションです。

<xsl:stylesheet version="1.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="kTestByData" match="Test"
  use="concat(Unit, '|', Unit2)"/>

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

 <xsl:template match=
  "Test[not(generate-id()
           = generate-id(key('kTestByData',concat(Unit, '|', Unit2))[last()])
            )]"/>
</xsl:stylesheet>

この変換が提供された XML ドキュメントに適用されると、次のようになります。

<xmeml>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
        </Test>
        <Test>
            <Unit>bcd</Unit>
            <Unit2>2345</Unit2>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>3456</Unit2>
        </Test>
        <Test>
            <Unit>cde</Unit>
            <Unit2>3456</Unit2>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
        </Test>
        <Test>
            <Unit>def</Unit>
            <Unit2>4567</Unit2>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
        </Test>
        <Test>
            <Unit>efg</Unit>
            <Unit2>2345</Unit2>
        </Test>
    </Doc>
</xmeml>

必要な正しい結果が生成されます。

<xmeml>
   <Doc>
      <Test>
         <Unit>bcd</Unit>
         <Unit2>2345</Unit2>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>3456</Unit2>
      </Test>
      <Test>
         <Unit>cde</Unit>
         <Unit2>3456</Unit2>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>def</Unit>
         <Unit2>4567</Unit2>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>1234</Unit2>
      </Test>
      <Test>
         <Unit>efg</Unit>
         <Unit2>2345</Unit2>
      </Test>
   </Doc>
</xmeml>

: 多数のノードを重複排除するノード セットの場合、Muenchian グループ化方法は、2 次 (O(N^2)) 兄弟比較グループ化よりも桁違いに高速です。


Ⅱ.XSLT 2.0 ソリューション:

II.1 シンプルな (非効率的で、長さが短いノードセットに適している) XSLT 2.0 ソリューションは次のとおりです。

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

 <xsl:template match=
  "Test[concat(Unit, '+', Unit2) = following::Test/concat(Unit, '+', Unit2)]"/>
</xsl:stylesheet>

II.2 を使用した効率的なソリューションxsl:for-each-group:

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

 <xsl:variable name="vLastInGroup" as="element()*">
  <xsl:for-each-group select="/*/Doc/Test"
       group-by="concat(Unit, '+', Unit2)">
   <xsl:sequence select="current-group()[last()]"/>
  </xsl:for-each-group>
 </xsl:variable>

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

 <xsl:template match=
 "Test[for $t in .
        return
         not($vLastInGroup[. is $t])
      ]"/>
</xsl:stylesheet>
于 2012-07-21T15:15:14.670 に答える