Dan*_*ans 1 xml xslt grouping key xslt-2.0
我试图显示按字母顺序排序的数据,以便以相同字母开头的项目位于不同的列中。在开始新列之前,这些列最多可容纳 10 个项目。我可以成功地按字母顺序划分数据并按每列的项目数划分,但我正在努力将这两个组合起来:
按字母顺序划分:
<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>
Run Code Online (Sandbox Code Playgroud)
除以每列的最大项目数:
<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>
Run Code Online (Sandbox Code Playgroud)
首选输出如下:
http://rookery9.aviary.com.s3.amazonaws.com/9676500/9676792_3580_625x625.jpg
一、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>
Run Code Online (Sandbox Code Playgroud)
当应用于此 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>
Run Code Online (Sandbox Code Playgroud)
产生所需的输出——名称按第一个字母开始排序,并放入每列 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>
Run Code Online (Sandbox Code Playgroud)
说明:
嵌套xsl:for-each-group- 首先按起始字符分组,然后对于每个这样确定和排序的组 - 按其项目所在的列数。
使用标准 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>
Run Code Online (Sandbox Code Playgroud)
当应用于同一个 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>
Run Code Online (Sandbox Code Playgroud)
说明:
使用Muenchian 分组方法,加上排序,我们获得(按排序顺序)name由所有以相同字符开头的名称组成的每组元素。
name上面获得的每组元素都是通过将模板应用于其第一个name元素来处理的。整个组、其长度和name组中元素的索引(默认值 = 1)作为参数传递。
匹配name元素的模板保证仅应用于列中的起始元素。它创建一个新column元素并在其中复制name此列的所有元素(从 index 开始$pInd并在 index 结束$pInd+$pColLength -1。没有要求这些元素应该是兄弟姐妹(它们不是)。如果不仅复制而且附加处理是每个都需要name,这可以通过将<xsl:copy-of>指令替换为:
——
<xsl:apply-templates mode="process" select=
"$pGroup
[position() >= $pInd
and
not(position() > $pInd + $pColLength -1)
]"/>
Run Code Online (Sandbox Code Playgroud)