按键和位置对 XSLT 进行分组和排序()

发布于 2024-12-02 21:30:26 字数 1984 浏览 1 评论 0 原文

我试图显示按字母顺序排序的数据,以便以相同字母开头的项目位于不同的列中。在开始新列之前,这些列最多可容纳 10 个项目。我可以成功地将数据按字母顺序划分并按每列的项目数划分,但我很难将 2 结合起来:

按字母顺序划分:

<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

I am trying to display data sorted alphabetically so that items that begin with the same letter are in separate columns. These columns can hold a maximum of 10 items before a new column is started. I can successfully divide the data up alphabetically AND divide it up by number of items per column but I am struggling to combine the 2:

Divided alphabetically:

<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>

Divided by max items per column:

<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>

Preferred output is like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一人独醉 2024-12-09 21:30:26

我。 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. 使用慕尼黑分组方法,加上排序,我们得到(按排序顺序)由所有以相同字符开头的名称组成的每组 name 元素.

  2. 上面获得的每组 name 元素都通过将模板应用于其第一个 name 元素来处理。整个组、其长度以及组中 name 元素的索引(默认 = 1)作为参数传递。

  3. name 元素匹配的模板保证仅应用于列中的起始元素。它创建一个新的 column 元素,并在其中复制该列的所有 name 元素(从索引 $pInd 开始,到索引 结束) $pInd+$pColLength -1 不要求这些元素应该是同级元素(它们不是),如果每个 name 不仅需要复制,还需要进行其他处理。这可以通过替换来完成 指令:

-

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

I. XSLT 2.0 Solution:

<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>

when applied on this XML document (as no such was provided in the question!!!):

<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>

produces the desired output -- names sorted by starting first letter and put into columns of 10 items each:

<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>

Explanation:

  1. Nested xsl:for-each-group -- first grouped by the starting character, then for each such determined and sorted group -- by the number of the column in which its items should be.

  2. Use of the standard XSLT 2.0 functions current-grouping-key() and current-group().

II.XSLT 1.0 Solution:

<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>

when applied on the same XML document (as above), the same desired output is produced -- names sorted by starting first letter and put into columns of 10 items each:

<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>

Explanation:

  1. Using the Muenchian grouping method, plus sorting, we obtain (in sorted order) each group of name elements consisting of all names starting with the same character.

  2. Every group of name elements as obtained above is processed by applying templates to its first name element. The whole group, its length and the index of the name element in the group (default = 1) are passed as parameters.

  3. The template matching a name element is guaranteed to be applied only on a starting element within a column. It creates a new column element and copies in it all name elements for this column (starting from index $pInd and ending at index $pInd+$pColLength -1. There is no requirement that these elements should be siblings (and they aren't). If not just copying but also additional processing is required for each name, this can be done here by replacing the <xsl:copy-of> instruction with:

-

<xsl:apply-templates mode="process" select=
           "$pGroup
               [position() >= $pInd
              and
                not(position() > $pInd + $pColLength -1)
                ]"/>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文