簡體   English   中英

XSLT 1.0按多個元素分組

[英]XSLT 1.0 grouping by multiple elements

關於這個主題,我有各種各樣的答案,但到目前為止,我還沒有找到解決方案。

我輸入的XML具有以下結構:

<RootNode>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM11</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM21</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM31</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM41</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM21</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM22</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM23</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM24</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABD</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD21</HEADELEMENT1>
    <HEADELEMENT2>HEAD22</HEADELEMENT2>
    <HEADELEMENT3>HEAD23</HEADELEMENT3>
    <HEADELEMENT4>HEAD24</HEADELEMENT4>
    <ITEMELEMENT1>ITEM31</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM32</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM33</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM34</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>002</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD31</HEADELEMENT1>
    <HEADELEMENT2>HEAD32</HEADELEMENT2>
    <HEADELEMENT3>HEAD33</HEADELEMENT3>
    <HEADELEMENT4>HEAD34</HEADELEMENT4>
    <ITEMELEMENT1>ITEM41</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM42</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM43</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM44</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM51</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM52</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM53</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM54</ITEMELEMENT4>
  </record>
</RootNode>

轉換的結果應如下所示:

<ResultXml>
  <record>
    <header>
      <KEYELEMENT1>001</KEYELEMENT1>
      <KEYELEMENT2>ABC</KEYELEMENT2>
      <KEYELEMENT3>EFG</KEYELEMENT3>
      <HEADELEMENT1>HEAD11</HEADELEMENT1>
      <HEADELEMENT2>HEAD12</HEADELEMENT2>
      <HEADELEMENT3>HEAD13</HEADELEMENT3>
      <HEADELEMENT4>HEAD14</HEADELEMENT4>
    </header>
    <item>
      <ITEMELEMENT1>ITEM11</ITEMELEMENT1>
      <ITEMELEMENT2>ITEM21</ITEMELEMENT2>
      <ITEMELEMENT3>ITEM31</ITEMELEMENT3>
      <ITEMELEMENT4>ITEM41</ITEMELEMENT4>       
    </item>     
    <item>
      <ITEMELEMENT1>ITEM21</ITEMELEMENT1>
      <ITEMELEMENT2>ITEM22</ITEMELEMENT2>
      <ITEMELEMENT3>ITEM23</ITEMELEMENT3>
      <ITEMELEMENT4>ITEM24</ITEMELEMENT4>       
    </item>     
    <item>
      <ITEMELEMENT1>ITEM51</ITEMELEMENT1>
      <ITEMELEMENT2>ITEM52</ITEMELEMENT2>
      <ITEMELEMENT3>ITEM53</ITEMELEMENT3>
      <ITEMELEMENT4>ITEM54</ITEMELEMENT4>       
    </item>
  </record>
  <record>
    <header>
      <KEYELEMENT1>001</KEYELEMENT1>
      <KEYELEMENT2>ABD</KEYELEMENT2>
      <KEYELEMENT3>EFG</KEYELEMENT3>
      <HEADELEMENT1>HEAD21</HEADELEMENT1>
      <HEADELEMENT2>HEAD22</HEADELEMENT2>
      <HEADELEMENT3>HEAD23</HEADELEMENT3>
      <HEADELEMENT4>HEAD24</HEADELEMENT4>
    </header>
    <item>
      <ITEMELEMENT1>ITEM31</ITEMELEMENT1>
      <ITEMELEMENT2>ITEM32</ITEMELEMENT2>
      <ITEMELEMENT3>ITEM33</ITEMELEMENT3>
      <ITEMELEMENT4>ITEM34</ITEMELEMENT4>       
    </item>
  </record>
  <record>
    <header>
      <KEYELEMENT1>002</KEYELEMENT1>
      <KEYELEMENT2>ABC</KEYELEMENT2>
      <KEYELEMENT3>EFG</KEYELEMENT3>
      <HEADELEMENT1>HEAD31</HEADELEMENT1>
      <HEADELEMENT2>HEAD32</HEADELEMENT2>
      <HEADELEMENT3>HEAD33</HEADELEMENT3>
      <HEADELEMENT4>HEAD34</HEADELEMENT4>
    </header>
    <item>
      <ITEMELEMENT1>ITEM41</ITEMELEMENT1>
      <ITEMELEMENT2>ITEM42</ITEMELEMENT2>
      <ITEMELEMENT3>ITEM43</ITEMELEMENT3>
      <ITEMELEMENT4>ITEM44</ITEMELEMENT4>       
    </item>
  </record>   
</ResultXml>

對於KEYELEMENT1,KEYELEMENT2和KEYELEMENT3中的每個不同值,我必須在結果中創建一個記錄。 其他標頭字段相同,並與鍵字段一起轉換為標頭元素。 項目應使用相同的鍵映射到記錄下。

我用以下方法嘗試了Muenchian方法:

    <xsl:key name="keyfields" match="record" use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>

<xsl:template match="/">
    <ResultXml>
        <xsl:apply-templates select="record[generate-id() = generate-id(key('keyfields',concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))[1])]" mode="header"/>
    </ResultXml>
</xsl:template>

<xsl:template match="record" mode="header">
    <record>
        <header>
            <KEYELEMENT1><xsl:value-of select="KEYELEMENT1"/></KEYELEMENT1>
            <KEYELEMENT2><xsl:value-of select="KEYELEMENT2"/></KEYELEMENT2>
            <KEYELEMENT3><xsl:value-of select="KEYELEMENT3"/></KEYELEMENT3>
            <HEADELEMENT1><xsl:value-of select="HEADELEMENT1"/></HEADELEMENT1>
            <HEADELEMENT2><xsl:value-of select="HEADELEMENT2"/></HEADELEMENT2>
            <HEADELEMENT3><xsl:value-of select="HEADELEMENT3"/></HEADELEMENT3>
            <HEADELEMENT4><xsl:value-of select="HEADELEMENT4"/></HEADELEMENT4>          
        </header>
    </record>       
</xsl:template>

但是我什至不能產生頭記錄。 任何幫助,將不勝感激。

如果將第一個模板匹配項從/更改為/* (或RootNode ),則可以正確獲取組。

之后,只需將項目分組為4組即可。一種方法是在謂詞中使用mod

這是一個例子。 我在Muenchian分組中使用count()而不是generate-id() ,但是可以通過任何一種方式完成。

例...

XML輸入

<RootNode>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM11</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM21</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM31</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM41</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM21</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM22</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM23</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM24</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABD</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD21</HEADELEMENT1>
    <HEADELEMENT2>HEAD22</HEADELEMENT2>
    <HEADELEMENT3>HEAD23</HEADELEMENT3>
    <HEADELEMENT4>HEAD24</HEADELEMENT4>
    <ITEMELEMENT1>ITEM31</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM32</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM33</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM34</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>002</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD31</HEADELEMENT1>
    <HEADELEMENT2>HEAD32</HEADELEMENT2>
    <HEADELEMENT3>HEAD33</HEADELEMENT3>
    <HEADELEMENT4>HEAD34</HEADELEMENT4>
    <ITEMELEMENT1>ITEM41</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM42</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM43</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM44</ITEMELEMENT4>
  </record>
  <record>
    <KEYELEMENT1>001</KEYELEMENT1>
    <KEYELEMENT2>ABC</KEYELEMENT2>
    <KEYELEMENT3>EFG</KEYELEMENT3>
    <HEADELEMENT1>HEAD11</HEADELEMENT1>
    <HEADELEMENT2>HEAD12</HEADELEMENT2>
    <HEADELEMENT3>HEAD13</HEADELEMENT3>
    <HEADELEMENT4>HEAD14</HEADELEMENT4>
    <ITEMELEMENT1>ITEM51</ITEMELEMENT1>
    <ITEMELEMENT2>ITEM52</ITEMELEMENT2>
    <ITEMELEMENT3>ITEM53</ITEMELEMENT3>
    <ITEMELEMENT4>ITEM54</ITEMELEMENT4>
  </record>
</RootNode>

XSLT 1.0

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

  <xsl:key name="keyfields" match="record"
    use="concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3)"/>

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

  <xsl:template match="/*">
    <ResultXml>
      <xsl:for-each
        select="record[count(.|key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))[1])=1]">
        <record>
          <header>
            <xsl:apply-templates
              select="*[starts-with(local-name(), 'KEYELEMENT') or starts-with(local-name(), 'HEADELEMENT')]"/>
          </header>
          <xsl:for-each select="key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))/*[starts-with(local-name(),'ITEMELEMENT')][position() mod 4 = 1]">
            <item>
              <xsl:apply-templates 
                select=".|following-sibling::*[starts-with(local-name(),'ITEMELEMENT')][position() >= 1 and 4 > position()]"/>
            </item>
          </xsl:for-each>
        </record>
      </xsl:for-each>
    </ResultXml>
  </xsl:template>

</xsl:stylesheet>

產量

<ResultXml>
   <record>
      <header>
         <KEYELEMENT1>001</KEYELEMENT1>
         <KEYELEMENT2>ABC</KEYELEMENT2>
         <KEYELEMENT3>EFG</KEYELEMENT3>
         <HEADELEMENT1>HEAD11</HEADELEMENT1>
         <HEADELEMENT2>HEAD12</HEADELEMENT2>
         <HEADELEMENT3>HEAD13</HEADELEMENT3>
         <HEADELEMENT4>HEAD14</HEADELEMENT4>
      </header>
      <item>
         <ITEMELEMENT1>ITEM11</ITEMELEMENT1>
         <ITEMELEMENT2>ITEM21</ITEMELEMENT2>
         <ITEMELEMENT3>ITEM31</ITEMELEMENT3>
         <ITEMELEMENT4>ITEM41</ITEMELEMENT4>
      </item>
      <item>
         <ITEMELEMENT1>ITEM21</ITEMELEMENT1>
         <ITEMELEMENT2>ITEM22</ITEMELEMENT2>
         <ITEMELEMENT3>ITEM23</ITEMELEMENT3>
         <ITEMELEMENT4>ITEM24</ITEMELEMENT4>
      </item>
      <item>
         <ITEMELEMENT1>ITEM51</ITEMELEMENT1>
         <ITEMELEMENT2>ITEM52</ITEMELEMENT2>
         <ITEMELEMENT3>ITEM53</ITEMELEMENT3>
         <ITEMELEMENT4>ITEM54</ITEMELEMENT4>
      </item>
   </record>
   <record>
      <header>
         <KEYELEMENT1>001</KEYELEMENT1>
         <KEYELEMENT2>ABD</KEYELEMENT2>
         <KEYELEMENT3>EFG</KEYELEMENT3>
         <HEADELEMENT1>HEAD21</HEADELEMENT1>
         <HEADELEMENT2>HEAD22</HEADELEMENT2>
         <HEADELEMENT3>HEAD23</HEADELEMENT3>
         <HEADELEMENT4>HEAD24</HEADELEMENT4>
      </header>
      <item>
         <ITEMELEMENT1>ITEM31</ITEMELEMENT1>
         <ITEMELEMENT2>ITEM32</ITEMELEMENT2>
         <ITEMELEMENT3>ITEM33</ITEMELEMENT3>
         <ITEMELEMENT4>ITEM34</ITEMELEMENT4>
      </item>
   </record>
   <record>
      <header>
         <KEYELEMENT1>002</KEYELEMENT1>
         <KEYELEMENT2>ABC</KEYELEMENT2>
         <KEYELEMENT3>EFG</KEYELEMENT3>
         <HEADELEMENT1>HEAD31</HEADELEMENT1>
         <HEADELEMENT2>HEAD32</HEADELEMENT2>
         <HEADELEMENT3>HEAD33</HEADELEMENT3>
         <HEADELEMENT4>HEAD34</HEADELEMENT4>
      </header>
      <item>
         <ITEMELEMENT1>ITEM41</ITEMELEMENT1>
         <ITEMELEMENT2>ITEM42</ITEMELEMENT2>
         <ITEMELEMENT3>ITEM43</ITEMELEMENT3>
         <ITEMELEMENT4>ITEM44</ITEMELEMENT4>
      </item>
   </record>
</ResultXml>

小提琴: http : //xsltfiddle.liberty-development.net/3Nqn5Yi

XSLT 1.0中的 Muenchiann分組需要一些有序的方法並仔細使用許多分組習慣用法

我們必須從創建鍵開始 ,對記錄進行分組,在這種情況下,在KEYELEMENT1 / / 2/2/3上進行。

然后,主模板(匹配RootNode )將“組”模板應用於每個組的第一條記錄。

“本集團”模板record

  • 打印開始record標簽,
  • 打印head元件填充有KEY ...... HEAD源元件,
  • 對當前組的所有成員調用“正常”模板,
  • 最后,打印結束record標簽。

“正常”模板record打印item充滿項...源元素的元素。

最后,您需要的是身份模板

因此,整個腳本如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="recs" match="record"
    use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>

  <xsl:template match="RootNode">
    <ResultXml>
      <!-- Apply "group" template to the first record in group -->
      <xsl:apply-templates select="record[generate-id() = generate-id(
        key('recs', concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))
        [1])]" mode="group"/>
    </ResultXml>
  </xsl:template>

  <!-- "Group" template for record -->
  <xsl:template match="record" mode="group">
    <record>
      <head>
        <xsl:copy-of select="*[starts-with(name(), 'KEY') or starts-with(name(), 'HEAD')]"/>
      </head>
      <!-- Apply "normal" template to all members of the current group -->
      <xsl:apply-templates select="key('recs',
        concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))"/>
    </record>
  </xsl:template>

  <!-- "Normal" template for record -->
  <xsl:template match="record">
    <item>
      <xsl:copy-of select="*[starts-with(name(), 'ITEM')]"/>
    </item>
  </xsl:template>

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

有關工作示例,請參見http://xsltfiddle.liberty-development.net/6qM2e2k

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM