XSLT,按年份排序和分组 [英] XSLT, sort and group by year-date

查看:192
本文介绍了XSLT,按年份排序和分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于Umbraco XSLT版本1.



我有aprox。 XML中的150条新闻。让我们这样说(全部是伪代码,直到我更熟悉这个xml / xslt):

 < news> 
< data alias = date> 2008-10-20< / data>
< / news>
< news>
< data alias = date> 2009-11-25< / data>
< / news>< news>
< data alias = date> 2009-11-20< / data>
< / news>等等等...

我想运行XML并创建html输出为新闻档案。 (标签不重要):

  2008 
一月
二月
...
2009
一月
二月
三月
等等

我只能想出一个嵌套for-each(伪代码):

  var year_counter = 2002 
var month_counter = 1
< xsl:value-of select =data [@alias ='date']>
... if month_counter == 12 end,else month_counter ++ ...
< / xsl:for-each>
... year_counter ++ ...
< / xsl:for-each>
pre>

但是一个编程人员经过10年的循环会产生120个循环,这就是糟糕的编码,因为我认为Umbraco缓存结果我并不担心,在这种情况下,最多会有150条记录。



有关如何排序和输出许多新闻项目的任何线索,并在每年和每年的几个月?



Br。Anders

解决方案

这个XML文件:

 < root> 
< news>
< data alias =日期> 2008-10-20< / data>
< / news>
< news>
< data alias =date> 2009-11-25< / data>
< / news>
< news>
< data别名= 日期 > 2009-11-20< /数据>
< / news>
< news>
< data alias =date> 2009-03-20< / data>
< / news>
< news>
< data alias =date> 2008-01-20< / data>
< / news>
< / root>

和此XSLT 1.0转换:

 < xsl:stylesheet 
version =1.0
xmlns:xsl =http://www.w3.org/1999/XSL/Transform
xmlns:cfg =http://tempuri.org/config
exclude-result-prefixes =cfg
>
< xsl:output method =xmlencoding =utf-8/>

<! - 通过它们的yyyy值(前4个字符)指示新闻 - >
< xsl:key
name =kNewsByY
match =news
use =substring(data [@ alias ='date'],1,4)
/>
<! - 通过其yyyy-mm值(前7个字符)索引新闻 - >
< xsl:key
name =kNewsByYM
match =news
use =substring(data [@ alias ='date'],1,7)
/>

<! - 翻译表(月份编号) - >
< config xmlns =http://tempuri.org/config>
<月>
< month id =06name =Jun/>
< month id =07name =Jul/>
< month id =08name =Aug/>
< month id =10name =Oct/>
< month id =12name =Dec/>
< /月>
< / config>

< xsl:template match =root>
< xsl:copy>
<! - 新闻由yyyy - >
news [
generate-id()
=
generate-id kNewsByY',子字符串(data [@ alias ='date'],1,4))[1])$ ​​b $ b]
>
< xsl:sort select =data [@ alias ='date']order =descending/>
< / xsl:apply-templates>
< / xsl:copy>
< / xsl:template>

<! - 年组将包含在< year>元素 - >
< xsl:template match =newsmode =year>
< year num ={$ y}>
<! - 将今年的新闻分组为yyyy-mm - >
< xsl:apply-templates mode =monthselect =
key('kNewsByY',$ y)[
generate-id()
= $ b $ ('kNewsByYM',substring(data [@ alias ='date'],1,7))[1])$ ​​b $ b]
>
< xsl:sort select =data [@ alias ='date']order =descending/>
< / xsl:apply-templates>
< / year>
< / xsl:template>

<! - 月份组将包含在<月>元素 - >
< xsl:template match =newsmode =month>
<! - 从配置中选择当前月份的标签 - >
<! - 处理当前yyyy-mm组的消息 - >
< xsl:apply-templates select =key('kNewsByYM',$ ym)>
< xsl:sort select =data [@ alias ='date']order =descending/>
< / xsl:apply-templates>
< /月>
< / xsl:template>

<! - 为了这个例子,新闻元素将被复制 - >
< xsl:template match =news>
< / xsl:template>
< / xsl:stylesheet>

应用转换时,会产生以下输出:

 < root> 
< year num =2009>
< month num =11label =Nov>
< news>
< data alias =date> 2009-11-25< / data>
< / news>
< news>
< data alias =date> 2009-11-20< / data>
< / news>
< /月>
< month num =03label =Mar>
< news>
< data alias =date> 2009-03-20< / data>
< / news>
< /月>
< / year>
< year num =2008>
< news>
< data alias =date> 2008-10-20< / data>
< / news>
< /月>
< month num =01label =Jan>
< news>
< data alias =date> 2008-01-20< / data>
< / news>
< /月>
< / year>
< / root>

它已经有了正确的结构,可以根据自己的需要调整实际外观。



解决方案是一个两阶段的Muenchian分组方法。在第一阶段,新闻项目按年份分组,第二阶段按年份分组。

请参阅我对的解释< xsl:key> key() 在这里。你不需要阅读另一个问题,虽然它是一个类似的问题。请阅读我答案的下半部分。

Regarding Umbraco XSLT version 1.

I have aprox. 150 news items in XML. Lets say like this (all is pseudocode until I get more familiar with this xml/xslt):

<news>
  <data alias=date>2008-10-20</data>
</news>
<news>
  <data alias=date>2009-11-25</data>
</news><news>
  <data alias=date>2009-11-20</data>
</news> etc. etc....

I would like to run through the XML and create html-output as a news archive. Something like (tags not important):

2008
  Jan
  Feb
  ...
2009
  Jan
  Feb
  Mar
  etc. etc.

I can only come up with a nested for-each (pseudocode):

var year_counter = 2002
var month_counter = 1
<xsl:for-each select="./data [@alias = 'date']=year_counter">
  <xsl:for-each select="./data [@alias = 'date']=month_counter">
    <xsl:value-of select="data [@alias = 'date']>
  "...if month_counter==12 end, else month_counter++ ..."
  </xsl:for-each>
"... year_counter ++ ..."
</xsl:for-each>

But a programmer pointet out that looping through 10 years will give 120 loops and that is bad coding. Since I think Umbraco caches the result I am not so concerned, plus in this case there will be a max. of 150 records.

Any clues on how to sort and output many news items and group them in year and group each year in months?

Br. Anders

解决方案

For the following solution I used this XML file:

<root>
  <news>
    <data alias="date">2008-10-20</data>
  </news>
  <news>
    <data alias="date">2009-11-25</data>
  </news>
  <news>
    <data alias="date">2009-11-20</data>
  </news>
  <news>
    <data alias="date">2009-03-20</data>
  </news>
  <news>
    <data alias="date">2008-01-20</data>
  </news>
</root>

and this XSLT 1.0 transformation:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:cfg="http://tempuri.org/config"
  exclude-result-prefixes="cfg"
>
  <xsl:output method="xml" encoding="utf-8" />

  <!-- index news by their "yyyy" value (first 4 chars) -->
  <xsl:key 
    name="kNewsByY"  
    match="news" 
    use="substring(data[@alias='date'], 1, 4)" 
  />
  <!-- index news by their "yyyy-mm" value (first 7 chars) -->
  <xsl:key 
    name="kNewsByYM" 
    match="news" 
    use="substring(data[@alias='date'], 1, 7)" 
  />

  <!-- translation table (month number to name) -->
  <config xmlns="http://tempuri.org/config">
    <months>
      <month id="01" name="Jan" />
      <month id="02" name="Feb" />
      <month id="03" name="Mar" />
      <month id="04" name="Apr" />
      <month id="05" name="May" />
      <month id="06" name="Jun" />
      <month id="07" name="Jul" />
      <month id="08" name="Aug" />
      <month id="09" name="Sep" />
      <month id="10" name="Oct" />
      <month id="11" name="Nov" />
      <month id="12" name="Dec" />
    </months>
  </config>

  <xsl:template match="root">
    <xsl:copy>
      <!-- group news by "yyyy" -->
      <xsl:apply-templates mode="year" select="
        news[
          generate-id()
          =
          generate-id(key('kNewsByY', substring(data[@alias='date'], 1, 4))[1])
        ]
      ">
        <xsl:sort select="data[@alias='date']" order="descending" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- year groups will be enclosed in a <year> element -->
  <xsl:template match="news" mode="year">
    <xsl:variable name="y" select="substring(data[@alias='date'], 1, 4)" />
    <year num="{$y}">
      <!-- group this year's news by "yyyy-mm" -->
      <xsl:apply-templates mode="month" select="
        key('kNewsByY', $y)[
          generate-id() 
          =
          generate-id(key('kNewsByYM', substring(data[@alias='date'], 1, 7))[1])
        ]
      ">
        <xsl:sort select="data[@alias='date']" order="descending" />
      </xsl:apply-templates>
    </year>
  </xsl:template>

  <!-- month groups will be enclosed in a <month> element -->
  <xsl:template match="news" mode="month">
    <xsl:variable name="ym" select="substring(data[@alias='date'], 1, 7)" />
    <xsl:variable name="m" select="substring-after($ym, '-')" />
    <!-- select the label of the current month from the config -->
    <xsl:variable name="label" select="document('')/*/cfg:config/cfg:months/cfg:month[@id = $m]/@name" />
    <month num="{$m}" label="{$label}">
      <!-- process news of the current "yyyy-mm" group -->
      <xsl:apply-templates select="key('kNewsByYM', $ym)">
        <xsl:sort select="data[@alias='date']" order="descending" />
      </xsl:apply-templates>
    </month>
  </xsl:template>

  <!-- for the sake of this example, news elements will just be copied -->
  <xsl:template match="news">
    <xsl:copy-of select="." />
  </xsl:template>
</xsl:stylesheet>

When the transformation is applied, the following output is produced:

<root>
  <year num="2009">
    <month num="11" label="Nov">
      <news>
        <data alias="date">2009-11-25</data>
      </news>
      <news>
        <data alias="date">2009-11-20</data>
      </news>
    </month>
    <month num="03" label="Mar">
      <news>
        <data alias="date">2009-03-20</data>
      </news>
    </month>
  </year>
  <year num="2008">
    <month num="10" label="Oct">
      <news>
        <data alias="date">2008-10-20</data>
      </news>
    </month>
    <month num="01" label="Jan">
      <news>
        <data alias="date">2008-01-20</data>
      </news>
    </month>
  </year>
</root>

It has the right structure already, you can adapt actual appearance to your own needs.

The solution is a two-phase Muenchian grouping approach. In the first phase, news items are grouped by year, in the second phase by year-month.

Please refer to my explanation of <xsl:key> and key() over here. You don't need to read the other question, though it is a similar problem. Just read the lower part of my answer.

这篇关于XSLT,按年份排序和分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆