0

現在、XSLT 2.0 を使用して大量のデータを処理しようとしています。私の目標は、データ全体で特定のノードが一意に発生するように特定のテンプレートを呼び出すことです。別のロジックに基づいて使用する必要がある他のテンプレートがあるため、「テンプレートの適用」を使用できません。xml は次のような構造になっています。

<root>
  <row>
     <date>date1</date>
     <child>
        <ID>001</ID>
     </child>
  </row>
  <row>
     <date>date2</date>
     <child>
        <ID>002</ID>
     </child>
  </row>
  <row>
     <date>date1</date>
     <child>
        <ID>002</ID>
     </child>
  </row>
  <row>
     <date>date3</date>
     <child>
        <ID>002</ID>
     </child>
  </row>
</root>

理想的には、このシナリオでは 2 つの一意の ID 001 と 002 があるため、その ID に表示される日付の数に関係なく、テンプレートを 2 回呼び出すことになります。キーまたは先行兄弟アプローチのいずれかを使用した例をいくつか見てきました。ただし、構文を正しく理解できないようです。私は次のアプローチを試しました:

呼び出されるテンプレート:

<xsl:template name='doSomething'/>
   <xsl:value-of select='child/ID'/>
   <xsl:value-of select='date'/>
</template>

====================

<xsl:for-each select='/root/row[not(child/ID = current()child/ID)]
   <xsl:call-template name='doSomething'/>
</xsl:for-each>

====================

<xsl:key name='IDs' match='root/row/child/ID' use='.'/>

<xsl:for-each select='root/row[generate-id() = generate-id(key("IDs",.)[1])]>
    <xsl:call-template name='doSomething'/>
</xsl:for-each>

====================

<xsl:for-each select='root/row/child/ID[not(. = preceding-sibling::row/child/ID)]>
   <xsl:call-template name='doSomething'/>
</xsl:for-each>

XSLT でこれほど洗練されたものを試すのはこれが初めてであり、キーの使用法と軸の構文がどのように機能するかを理解するのにまだ苦労しているため、これが恐ろしいコーディングである場合は申し訳ありません。通常、2.0 では for-each-group を使用します。ただし、ここで for-each-group を試行すると、一意のエントリではなくすべてのエントリが取得されるため、グループ化の仕組みを完全には理解していないと思います。私の最初の試みはこれでした:

<xsl:for-each-group select='root/row' group-by='child/ID'>
    <xsl:call-template name='doSomething'/>
</xsl:for-each-group>

====================

私もこれを試しました:

<xsl:for-each-group select='root/row' group-by='child/ID[1]'>
   <xsl:call-template name='doSomething'/>
</xsl:for-each-group>

====================

これが完全に正しいわけではないことはわかっていますが、アイデアが尽きて実験していました。これを解決するための指示や支援をいただければ幸いです。あなたが提供できる助けを前もって感謝します。

これが私の望ましい出力です:

001日付1 002日付2

しかし、私は得ています:

001日付1 002日付2 002日付1 002日付3

編集: フィードバックをお寄せいただきありがとうございます。コードのかなり重要な部分を省略していることに気付きました。各 ID には、取引日を表す日付も関連付けられています。また、for-each-group を使用して ID でグループ化できますが、その ID に関連付けられたすべての日付を取得し続け、その ID を含むすべてのエントリではなく、一意の ID のテンプレートのみを呼び出したいと考えています。今起こってる。サンプル出力と電流出力を追加しました。

apply-template の仕組みを誤解している可能性があります。apply-templates を使用すると、xslt 内のすべてのテンプレートが適用されると思いました。特定の条件下で使用されるテンプレートが他に 4 つあります。実際の入力 xml には約 40 の子ノードがあり、ロジックと情報の処理に使用されます。

詳細が必要な場合はお知らせください。

編集:

さらに調査を行った後、キーを使用するのが良い方法のようです。ただし、構文を正しく取得できないようです。これが私の試みです。誰かがそれを修正するのを手伝ってくれますか?

<xsl:key name='IDs' match='child' use='ID'/>

<xsl:template match='/'>
   <xsl:for-each select='root/row/child[generate-id(.) = generate-id(key("IDs", ID)[1])]>
       <xsl:call-template name='doSomething'/>
   </xsl:for-each>
</xsl:template>

明確にしていただきありがとうございます。

4

3 に答える 3

0

解決

フィードバックを提供してくれたすべての人に感謝します。週末にさらに調査を行い、少し実験した結果、解決策を得ることができました。

入力:

<root>
  <row>
     <date>date1</date>
     <child>
         <id>001</id>
     </child>
  </row>
  <row>
     <date>date1</date>
     <child>
         <id>002</id>
     </child>
  </row>
  <row>
     <date>date2</date>
     <child>
         <id>002</id>
     </child>
  </row>
</root>

XSLT:

<xsl:for-each select='root/row'>
    <xsl:if test='preceding-sibling::row[1]/child/id != child/id'>
         <xsl:call-template name='doSomething'/>
    </xsl:if>
</xsl:for-each>

出力:

001date1、002date1

于 2013-01-14T17:00:00.243 に答える
0

必要な出力、コード、取得した結果を示して、問題が何であるかを実際に説明していません。

使用に問題は見られません。または、投稿したものと一緒apply-templatesに使用することを主張する場合も問題はありません。call-templatefor-each-group

両方のアプローチを示すサンプルを次に示します。

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output indent="yes"/>

<xsl:template match="/">
  <apply-templates>
     <xsl:for-each-group select="root/row" group-by="child/ID">
       <xsl:apply-templates select="."/>
     </xsl:for-each-group>
   </apply-templates>
   <call-template>
     <xsl:for-each-group select="root/row" group-by="child/ID">
       <xsl:call-template name="foo"/>
     </xsl:for-each-group>
   </call-template>
</xsl:template>

<xsl:template match="root/row">
  <xsl:copy-of select="."/>
</xsl:template>

<xsl:template name="foo">
  <xsl:copy-of select="."/>
</xsl:template>

</xsl:stylesheet>

入力に適用した場合

<root>
  <row>
     <child>
        <ID>value</ID>
     </child>
  </row>
  <row>
     <child>
        <ID>value2</ID>
     </child>
  </row>
  <row>
     <child>
        <ID>value2</ID>
     </child>
  </row>
</root>

Saxon 9.4では出力が得られます

<apply-templates>
   <row>
     <child>
        <ID>value</ID>
     </child>
  </row>
   <row>
     <child>
        <ID>value2</ID>
     </child>
  </row>
</apply-templates>
<call-template>
   <row>
     <child>
        <ID>value</ID>
     </child>
  </row>
   <row>
     <child>
        <ID>value2</ID>
     </child>
  </row>
</call-template>

row私があなたの説明を理解している限り、両方のアプローチがあなたが興味を持っている要素を処理します。

それでも問題が解決しない場合は、問題を再現できるように、XSLT の最小限の完全なサンプル、取得した出力、必要な出力、使用している XSLT 2.0 プロセッサの詳細を提示してください。

于 2013-01-11T10:35:58.230 に答える
0

この返信が遅れて申し訳ありません。これが私が思いついた解決策です。それが最もエレガントなソリューションかどうかはわかりませんが、私にとっては非常にうまく機能しました。おそらく、これは不十分な解決策ですが、フィードバックをいただければ幸いです。

    <xsl:for-each-group select='root/Row' group-by='concat(child/ID,date)'>
        <xsl:sort select='child/ID'/>
        <xsl:call-template name='DoSomething'/>
    </xsl:for-each-group>

ありがとうございました。

于 2013-02-18T05:11:32.683 に答える