2011-09-04 81 views
1

我試圖顯示按字母順序排序的數據,以便以相同字母開頭的項目位於單獨的列中。在啓動新列之前,這些列最多可以保留10個項目。我可以成功地分割數據高達字母順序和每列項數除以它,但我很努力結合起來,2:按鍵和位置對XSLT進行分組和排序()

按字母順序分爲:

<xsl:template match="/"> 
<xsl:key name="node-by-first-letter" match="node" use="substring(@email, 1, 1)" /> 


<div class="scroller-panel"> 
    <xsl:for-each select="msxml:node-set($members)/node[count(. | key('node-by-first-letter', substring(@email, 1, 1))[1]) = 1]"> 
     <xsl:sort select="@email" order="ascending"/> 

      <xsl:apply-templates select="." mode="group" /> 
</xsl:for-each></div></xsl:template> 
<xsl:template match="node" mode="group"> 
    <div class="column-312 scroller-item people-search-column fade-panel"> 
    <h2> 
     <xsl:value-of select="Exslt.ExsltStrings:uppercase(substring(@email,1,1))"/> 
    </h2> 
    <ul class="stripe-list"> 
     <xsl:apply-templates select="key('node-by-first-letter', substring(@email, 1, 1))" mode="item"> 
      <xsl:sort select="@email" /> 
     </xsl:apply-templates>  
    </ul> 
    </div> 
</xsl:template> 
<xsl:template match="node" mode="item"> 
      <li> 
       <a href="4.0.1.person.profile.html"> 
        <xsl:value-of select="@email"/> 
       </a> 
      </li> 
</xsl:template> 

每列最大項目分爲:

<xsl:for-each select="msxml:node-set($members)/members/member[position() mod 10 = 1]"> 
<ul> 
<xsl:for-each select=". | following-sibling::*[not(position() >= 10)]"> 
<li> 
<xsl:value-of select="@email"/> 
</li> 
</xsl:for-each> 
</ul> 
</xsl:for-each> 

優選輸出是這樣的:

http://rookery9.aviary.com.s3.amazonaws.com/9676500/9676792_3580_625x625.jpg

+1

提供樣品輸入和所希望的輸出 –

+0

爲什麼使用未混合兩種溶液多通變換? –

+0

優秀的問題,+1。查看我的答案,獲得一個完整的解決方案,演示了幾種技術:1)基於值的起始字符的Muenchian分組; 2)不是兄弟姐妹的物品的位置分組(可能來自不同的文檔,而可能來自不同的文檔)。 –

回答

4

I. XSLT 2.0解決方案

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:param name="pColLength" as="xs:integer" select="10"/> 

<xsl:template match="/*"> 
    <names> 
     <xsl:for-each-group select="name" 
          group-by="substring(.,1,1)"> 
     <xsl:sort select="current-grouping-key()"/> 
     <xsl:for-each-group select="current-group()" 
      group-by="(position()-1) idiv $pColLength"> 
      <column> 
      <xsl:copy-of select="current-group()"/> 
      </column> 
     </xsl:for-each-group> 
     </xsl:for-each-group> 
    </names> 
</xsl:template> 
</xsl:stylesheet> 

當此XML文檔上施加(如沒有這樣的在的問題提供!!!):

<names> 
     <name>T A</name> 
     <name>T B</name> 
     <name>T C</name> 
     <name>T D</name> 
     <name>T E</name> 
     <name>T F</name> 
     <name>T G</name> 
     <name>T H</name> 
     <name>T I</name> 
     <name>T J</name> 
     <name>T K</name> 
     <name>T L</name> 
     <name>A A</name> 
     <name>A B</name> 
     <name>A C</name> 
     <name>A D</name> 
     <name>A E</name> 
     <name>A F</name> 
     <name>A G</name> 
     <name>A H</name> 
     <name>A I</name> 
     <name>A J</name> 
     <name>A K</name> 
     <name>A L</name> 
     <name>X A</name> 
     <name>X B</name> 
     <name>X C</name> 
     <name>X D</name> 
     <name>X E</name> 
     <name>X F</name> 
     <name>X G</name> 
     <name>X H</name> 
     <name>X I</name> 
     <name>X J</name> 
     <name>X K</name> 
     <name>X L</name> 
     <name>R A</name> 
     <name>R B</name> 
     <name>R C</name> 
     <name>R D</name> 
     <name>R E</name> 
     <name>R F</name> 
     <name>R G</name> 
     <name>R H</name> 
     <name>R I</name> 
     <name>R J</name> 
     <name>R K</name> 
     <name>R L</name> 
</names> 

產生所需輸出 - 名稱按起始第一個字母排序並放入每個10個項目的列中

<names> 
    <column> 
     <name>A A</name> 
     <name>A B</name> 
     <name>A C</name> 
     <name>A D</name> 
     <name>A E</name> 
     <name>A F</name> 
     <name>A G</name> 
     <name>A H</name> 
     <name>A I</name> 
     <name>A J</name> 
    </column> 
    <column> 
     <name>A K</name> 
     <name>A L</name> 
    </column> 
    <column> 
     <name>R A</name> 
     <name>R B</name> 
     <name>R C</name> 
     <name>R D</name> 
     <name>R E</name> 
     <name>R F</name> 
     <name>R G</name> 
     <name>R H</name> 
     <name>R I</name> 
     <name>R J</name> 
    </column> 
    <column> 
     <name>R K</name> 
     <name>R L</name> 
    </column> 
    <column> 
     <name>T A</name> 
     <name>T B</name> 
     <name>T C</name> 
     <name>T D</name> 
     <name>T E</name> 
     <name>T F</name> 
     <name>T G</name> 
     <name>T H</name> 
     <name>T I</name> 
     <name>T J</name> 
    </column> 
    <column> 
     <name>T K</name> 
     <name>T L</name> 
    </column> 
    <column> 
     <name>X A</name> 
     <name>X B</name> 
     <name>X C</name> 
     <name>X D</name> 
     <name>X E</name> 
     <name>X F</name> 
     <name>X G</name> 
     <name>X H</name> 
     <name>X I</name> 
     <name>X J</name> 
    </column> 
    <column> 
     <name>X K</name> 
     <name>X L</name> 
    </column> 
</names> 

說明

  1. 嵌套xsl:for-each-group - 首先由起始字符分組,然後對每個這樣的確定和排序組 - 通過在其項應的列的數目。

  2. 使用標準的XSLT的2.0函數current-grouping-key()current-group()

II.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:param name="pColLength" select="10"/> 

<xsl:key name="kStarting" match="name" 
    use="substring(.,1,1)"/> 

<xsl:template match="/*"> 
    <names> 
      <xsl:for-each select= 
      "name 
       [generate-id() 
       = 
       generate-id(key('kStarting', substring(.,1,1))[1]) 
       ] 
      "> 
      <xsl:sort select="substring(.,1,1)"/> 

      <xsl:variable name="vgroupNames" select= 
       "key('kStarting', substring(.,1,1))"/> 

      <xsl:apply-templates select="$vgroupNames[1]"> 
       <xsl:with-param name="pGroup" select="$vgroupNames"/> 
       <xsl:with-param name="pGroupLength" select= 
       "count($vgroupNames)"/> 
      </xsl:apply-templates> 
      </xsl:for-each> 
    </names> 
</xsl:template> 

<xsl:template match="name"> 
    <xsl:param name="pGroup"/> 
    <xsl:param name="pGroupLength"/> 
    <xsl:param name="pInd" select="1"/> 

    <xsl:if test="not($pInd > $pGroupLength)"> 
     <column> 
     <xsl:copy-of select= 
     "$pGroup 
      [position() >= $pInd 
      and 
      not(position() > $pInd + $pColLength -1) 
      ]"/> 
     </column> 

     <xsl:apply-templates select= 
     "$pGroup[position() = $pInd + $pColLength]"> 
     <xsl:with-param name="pGroup" select="$pGroup"/> 
     <xsl:with-param name="pGroupLength" select="$pGroupLength"/> 
     <xsl:with-param name="pInd" select="$pInd + $pColLength"/> 
     </xsl:apply-templates> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

當對相同的XML文檔施加(如上),相同的期望輸出產生 - 由第一啓動排序名字母並放入每欄10項

<names> 
    <column> 
     <name>A A</name> 
     <name>A B</name> 
     <name>A C</name> 
     <name>A D</name> 
     <name>A E</name> 
     <name>A F</name> 
     <name>A G</name> 
     <name>A H</name> 
     <name>A I</name> 
     <name>A J</name> 
    </column> 
    <column> 
     <name>A K</name> 
     <name>A L</name> 
    </column> 
    <column> 
     <name>R A</name> 
     <name>R B</name> 
     <name>R C</name> 
     <name>R D</name> 
     <name>R E</name> 
     <name>R F</name> 
     <name>R G</name> 
     <name>R H</name> 
     <name>R I</name> 
     <name>R J</name> 
    </column> 
    <column> 
     <name>R K</name> 
     <name>R L</name> 
    </column> 
    <column> 
     <name>T A</name> 
     <name>T B</name> 
     <name>T C</name> 
     <name>T D</name> 
     <name>T E</name> 
     <name>T F</name> 
     <name>T G</name> 
     <name>T H</name> 
     <name>T I</name> 
     <name>T J</name> 
    </column> 
    <column> 
     <name>T K</name> 
     <name>T L</name> 
    </column> 
    <column> 
     <name>X A</name> 
     <name>X B</name> 
     <name>X C</name> 
     <name>X D</name> 
     <name>X E</name> 
     <name>X F</name> 
     <name>X G</name> 
     <name>X H</name> 
     <name>X I</name> 
     <name>X J</name> 
    </column> 
    <column> 
     <name>X K</name> 
     <name>X L</name> 
    </column> 
</names> 

說明

  1. 使用Muenchian grouping method,外加整理,得到(按排序順序)各組羣由開始具有相同字符的所有名稱的name元件。

  2. 如上獲得name元件的每一個基團是通過將模板至其第一name元件處理。整個組,其長度和組中name元素的索引(默認值= 1)作爲參數傳遞。

  3. name元素匹配的模板保證僅適用於列內的起始元素。它會創建一個新的column元素,並在其中爲此列複製所有name元素(從索引​​開始,並以索引$pInd+$pColLength -1結束。沒有要求這些元素應該是兄弟(並且它們不是)。還需要對每個name額外的處理,這可以在這裏通過用替換<xsl:copy-of>指令完成:

-

<xsl:apply-templates mode="process" select= 
      "$pGroup 
       [position() >= $pInd 
       and 
       not(position() > $pInd + $pColLength -1) 
       ]"/> 
+0

+1爲好的答案。我建議'node-set()',因爲從OP信息開始,我無法給出一個完整的解決方案(輸入缺失),並且沒有考慮如你正確做的那樣自己創建一個。這確實是正確的方法。 –

+0

@empo:從這個答案中可以學到的是,爲了將節點分組爲列,節點不必是兄弟節點。 –