2011-09-04 80 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:从这个答案中可以学到的是,为了将节点分组为列,节点不必是兄弟节点。 –