XSLT,按年份日期排序和分组
关于Umbraco XSLT版本1 我有一个药盒。150条XML新闻。让我们这样说(在我更加熟悉xml/xslt之前,所有代码都是伪代码): 我只能为每种类型提供一个嵌套的(伪代码):XSLT,按年份日期排序和分组,xslt,sorting,umbraco,foreach,xslt-grouping,Xslt,Sorting,Umbraco,Foreach,Xslt Grouping,关于Umbraco XSLT版本1 我有一个药盒。150条XML新闻。让我们这样说(在我更加熟悉xml/xslt之前,所有代码都是伪代码): 我只能为每种类型提供一个嵌套的(伪代码): var年份\u计数器=2002 变量月份计数器=1 您需要的是所谓的方法,它正好解决XSLT的这个问题/模式 基本上,它通过查找唯一的键并在所使用的键中包含的条目上循环来进行分组。除了lucero之外,请检查以避免月份名称被删除的问题。您不能在XSLT中使用month_counter+,它不是一种过程语言,也不是
var年份\u计数器=2002
变量月份计数器=1
您需要的是所谓的方法,它正好解决XSLT的这个问题/模式
基本上,它通过查找唯一的键并在所使用的键中包含的条目上循环来进行分组。除了lucero之外,请检查以避免月份名称被删除的问题。您不能在XSLT中使用month_counter+,它不是一种过程语言,也不是XSLT的工作方式。所以,如果不这样做,担心这样做效率低下是没有意义的
这看起来像是XSLT中的一大难题。我的XSLT不够新鲜,无法尝试并实际实现它。但这里有两种方法:
(一)
- 使用xsl:key提取所有唯一年份-
- 然后重复这些年。每年做什么
- 使用xsl:key提取所有月份
- 每个月做什么
2) (如果可行,似乎更容易。)
- 按日期排序,将排序后的数组保存在变量中
- 迭代此变量(变量保存排序数组很重要)
- 每次看前面的兄弟姐妹。如果其年/月不等于当前元素,请写入相应的标题
3) 忘记XSLT,使用真正的编程语言。对于以下解决方案,我使用了此XML文件:
<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>
2008-10-20
2009-11-25
2009-11-20
2009-03-20
2008-01-20
这个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="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>
应用转换时,将生成以下输出:
<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>
2009-11-25
2009-11-20
2009-03-20
2008-10-20
2008-01-20
它已经有了正确的结构,您可以根据自己的需要调整实际外观
解决方案是两阶段的Muenchian分组方法。在第一阶段,新闻项目按年度分组,在第二阶段按年度和月份分组
请参阅我对
和key()
的解释。你不需要阅读另一个问题,尽管这是一个类似的问题。请阅读我答案的下半部分。投票后,我去检查了一些东西,结果发现我实际上没有使用这种方法——我做了一些不对的事情!我运行的是粗略的解决方案:包装——但就我(和你)拥有的数据大小而言,它是有效的!谢谢你的链接,卢科。我已经开始阅读关于门钦族的书籍。感谢你的评论,Murph,这是一个很好的基础,为“快速肮脏”的解决方案,我将开始与,直到我得到了“Muenchian分组”的工作。比尔。andersintresisting使用document()
函数(空URL返回XSL转换文档-我希望得到正在处理的文档)。是否在某个地方记录了这一点,并且可以跨不同的1.0兼容XSLT引擎进行移植?这是记录在案的标准行为。所有处理器都会这样运行。哇。谢谢。我是XSLT新手,我猜可能会有一个内置函数:-)您的工作似乎是一个完整的解决方案,我已经开始将您的解决方案包含在网页上。虽然仍在进行中,但我会将此标记为一个答案,并继续阅读关于Muenchian分组的内容,并将您的代码集成到我的宏中。BR谢谢你,Andersy欢迎你。:)在XSLT2.0中,在分组方面有了很大的改进,它比1.0中更自然。但据我所知,Umbraco不支持2.0,对吗?是的,Umbraco只支持1.0版。我听说微软试图将他们的LINQ2XMl而不是开发对XSLT 2.0的支持引入到.net框架中(Umbraco就是基于这个框架的)。不知道这是否正确,我只是尝试传递我从程序员那里得到的输入:-)
<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>
<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>
<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>