1

入力:

<root><element>
  <small>a</small>
  <Large>B</Large>
  <Time>301</Time></element><element>
  <small>a</small>
  <Large>B</Large>
  <Time>322</Time></element><element>
  <small>b</small>
  <Large>A</Large>
  <Time>274</Time></element><element>
  <small>c</small>
  <Large>B</Large>
  <Time>325</Time></element><element>
  <small>b</small>
  <Large>A</Large>
  <Time>301</Time></element></root>

xsltを記述して、small要素とLarge要素がペアになる回数を確認し、その数をsmallnumタグにリストし、その回数の反復時間をtotsmalltimeタグに追加する必要があります。

出力:

<root><element>
  <small>a</small>
  <Large>B</Large>
  <smallnum>2</smallnum>
  <totsmalltime>623</totsmalltime></element><element>
  <small>b</small>
  <Large>A</Large>
  <smallnum>2</smallnum>
  <totsmalltime>575</totsmalltime></element><element>
  <small>c</small>
  <Large>B</Large>
  <smallnum>1</smallnum>
  <totsmalltime>325</totsmalltime></element></root>
4

3 に答える 3

2

XSLT1.0 でこれを行うには、Muenchian Grouping を使用します。あなたの場合、最初の先行する大小の要素の組み合わせによって時間要素をグループしてます。これは、次のキーを定義することから始めることを意味します

<xsl:key 
   name="pairs" 
   match="Time" 
   use="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])" />

次に、特定のキーのグループで最初に表示されるTime要素が必要になります。これは次のように行います。

<xsl:apply-templates 
  select="element/Time[
     generate-id()
     = generate-id(
         key(
           'pairs', 
           concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])
          )[1])]" />

次に、たとえば、グループ内のすべての要素の値であるsmallnum値を取得するには、単純にこれを実行します。ここで、 $keyは次のように定義されます。concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])

<xsl:value-of select="count(key('pairs', $key))" />

totsmalltime要素には、count の代わりに sum を使用します。

ここに完全な XSLT があります

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

   <xsl:key name="pairs" match="Time" use="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])"/>

   <xsl:template match="/root">
      <root>
         <xsl:apply-templates select="element/Time[generate-id() = generate-id(key('pairs', concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1]))[1])]"/>
      </root>
   </xsl:template>

   <xsl:template match="Time">
      <xsl:variable name="small" select="preceding-sibling::small[1]"/>
      <xsl:variable name="Large" select="preceding-sibling::Large[1]"/>
      <xsl:variable name="key" select="concat($Large, '|', $small)"/>
      <element>
         <xsl:copy-of select="$small"/>
         <xsl:copy-of select="$Large"/>
         <smallnum>
            <xsl:value-of select="count(key('pairs', $key))"/>
         </smallnum>
         <totsmalltime>
            <xsl:value-of select="sum(key('pairs', $key))"/>
         </totsmalltime>
      </element>
   </xsl:template>
</xsl:stylesheet>

XML に適用すると、以下が出力されます。

<root>
   <element>
      <small>a</small>
      <Large>B</Large>
      <smallnum>2</smallnum>
      <totsmalltime>623</totsmalltime>
   </element>
   <element>
      <small>b</small>
      <Large>A</Large>
      <smallnum>2</smallnum>
      <totsmalltime>575</totsmalltime>
   </element>
   <element>
      <small>c</small>
      <Large>B</Large>
      <smallnum>1</smallnum>
      <totsmalltime>325</totsmalltime>
   </element>
</root>

編集: XSLT2.0 では、カウントと合計を行うときにcurrent-group()と共にxsl:for-each-group要素を使用できます。

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

   <xsl:template match="/root">
      <root>
         <xsl:for-each-group select="element/Time" group-by="concat(preceding-sibling::Large[1], '|', preceding-sibling::small[1])">
            <element>
               <xsl:copy-of select="preceding-sibling::small[1]"/>
               <xsl:copy-of select="preceding-sibling::Large[1]"/>
               <smallnum>
                  <xsl:value-of select="count(current-group())"/>
               </smallnum>
               <totsmalltime>
                  <xsl:value-of select="sum(current-group())"/>
               </totsmalltime>
            </element>
         </xsl:for-each-group>
      </root>
   </xsl:template>
</xsl:stylesheet>

これも同じ XML を出力するはずです。

于 2012-10-23T21:26:26.060 に答える
0

あなたが求めている手法はミュンチアングループ化と呼ばれ、要素と値elementの組み合わせによって要素をグループ化する必要があります。smallLarge

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="smallLarge" match="element"
        use="concat(small, '_', Large)" />

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="root/element[generate-id() = generate-id(
             key('smallLarge', concat(small, '_', Large)[1])]" />
    </root>
  </xsl:template>

  <xsl:template match="element">
    <element>
      <small><xsl:value-of select="small" /></small>
      <Large><xsl:value-of select="Large" /></Large>
      <smallnum><xsl:value-of select="count(key('smallLarge',
                  concat(small, '_', Large)))" /></smallnum>
      <totsmalltime><xsl:value-of select="sum(key('smallLarge',
                  concat(small, '_', Large))/Time)" /></totsmalltime>
    </element>
  </xsl:template>
</xsl:stylesheet>

興味深い行は

      <xsl:apply-templates select="root/element[generate-id() = generate-id(
             key('smallLarge', concat(small, '_', Large)[1])]" />

これは、各キー値の最初のgenerate-id要素のみを選択するために使用されます。したがって、テンプレートは/の組み合わせごとに1回呼び出され、そのテンプレートはキーを使用して、その特定のキー値について常にカウントおよび合計できます。 elementelementsmallLarge

PS元のXMLの例のインデントはひどいです。要素に気付くまでに数回の読み取りが必要でした。最初は、 1つの長いシーケンスと兄弟elementのように見えました...smallLargeTime

于 2012-10-23T21:35:47.447 に答える
0

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

これは、完全に「プッシュスタイル」であるより短いソリューションです:)

<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="kElem" match="element"
  use="concat(small, '+', Large)"/>

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

 <xsl:template match=
 "element[generate-id()=generate-id(key('kElem',concat(small, '+', Large))[1])]">
  <xsl:variable name="vGroup" select="key('kElem',concat(small, '+', Large))"/>

  <element>
   <xsl:apply-templates/>
   <smallnum><xsl:value-of select="count($vGroup)"/></smallnum>
   <totsmalltime><xsl:value-of select="sum($vGroup/Time)"/></totsmalltime>
  </element>
 </xsl:template>
 <xsl:template match="element|Time"/>
</xsl:stylesheet>

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

<root>
    <element>
        <small>a</small>
        <Large>B</Large>
        <Time>301</Time>
    </element>
    <element>
        <small>a</small>
        <Large>B</Large>
        <Time>322</Time>
    </element>
    <element>
        <small>b</small>
        <Large>A</Large>
        <Time>274</Time>
    </element>
    <element>
        <small>c</small>
        <Large>B</Large>
        <Time>325</Time>
    </element>
    <element>
        <small>b</small>
        <Large>A</Large>
        <Time>301</Time>
    </element>
</root>

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

<root>
   <element>
      <small>a</small>
      <Large>B</Large>
      <smallnum>2</smallnum>
      <totsmalltime>623</totsmalltime>
   </element>
   <element>
      <small>b</small>
      <Large>A</Large>
      <smallnum>2</smallnum>
      <totsmalltime>575</totsmalltime>
   </element>
   <element>
      <small>c</small>
      <Large>B</Large>
      <smallnum>1</smallnum>
      <totsmalltime>325</totsmalltime>
   </element>
</root>

説明:

  1. アイデンティティ ルールの適切な使用とオーバーライド。

  2. Muenchian Grouping Methodの適切な使用。


Ⅱ.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:template match="/*">
  <root>
   <xsl:for-each-group select="*" group-by="concat(small, '+', Large)">
    <element>
     <xsl:sequence select="small, Large"/>
     <smallnum>
       <xsl:sequence select="count(current-group())"/>
     </smallnum>
     <totsmalltime>
      <xsl:sequence select="sum(current-group()/Time)"/>
     </totsmalltime>
    </element>
   </xsl:for-each-group>
  </root>
 </xsl:template>
</xsl:stylesheet>

この変換を同じ XML ドキュメント (上記) に適用すると、同じ正しい結果が生成されます。

<root>
   <element>
      <small>a</small>
      <Large>B</Large>
      <smallnum>2</smallnum>
      <totsmalltime>623</totsmalltime>
   </element>
   <element>
      <small>b</small>
      <Large>A</Large>
      <smallnum>2</smallnum>
      <totsmalltime>575</totsmalltime>
   </element>
   <element>
      <small>c</small>
      <Large>B</Large>
      <smallnum>1</smallnum>
      <totsmalltime>325</totsmalltime>
   </element>
</root>

説明:

  1. <xsl:for-each-group>withgroup-by属性の適切な使用。

  2. 機能の適切な使用current-group()

于 2012-10-24T03:17:11.207 に答える