XSLT,按年份排序和分组 [英] XSLT, sort and group by year-date
问题描述
我有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
pre>
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>
但是一个编程人员经过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>
andkey()
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屋!