XSLT,按年份日期排序和分组

发布于 2024-08-11 09:40:21 字数 1095 浏览 11 评论 0原文

关于 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> etc. etc....

我想运行 XML 并创建 html 输出作为新闻存档。像这样的东西(标签不重要):

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

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

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>

但是程序员指出,循环 10 年将给出 120 个循环,这是糟糕的编码。因为我认为 Umbraco 缓存了结果,所以我不太关心,而且在这种情况下会有一个最大值。共 150 条记录。

有关如何对许多新闻项目进行排序和输出并将其按年份分组以及每年按月份分组的任何线索?

Br。安德斯

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

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

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

发布评论

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

评论(4

埋情葬爱 2024-08-18 09:40:22

您需要的是所谓的 Muenchian Grouping 方法,它正是解决这个问题XSLT 的问题/模式。

基本上,它通过查找唯一键并循环使用的键中包含的条目来进行分组。

What you need is the so-called Muenchian Grouping method, which addresses exactly this problem/pattern for XSLT.

Basically, it groups by finding unique keys and looping over the entries contained in the key being used.

冰之心 2024-08-18 09:40:22

除了 lucero 之外,请查看 Xsl 分组重复问题,以避免月份名称被删除的问题

in addition to lucero, check out Xsl grouping duplicates problem for avoiding problems with month names being removes

枫以 2024-08-18 09:40:22

您不能在 XSLT 中执行 Month_counter++,它不是一种过程语言,也不是 XSLT 的工作方式。因此,如果这不能以这种方式工作,那么担心效率低下是毫无意义的。

这看起来像是 XSLT 中的一大难题。我的 XSLT 还不够新鲜,无法尝试和实际实现它。但这里有两种方法:

1)

  • 使用 xsl:key 提取所有唯一的年份 -
  • 然后迭代这些年份。每年做
  • 使用 xsl:key 提取所有月份
  • 每个月做

2)(如果可行的话,似乎更容易。)

  • 按日期对它们进行排序,将排序后的数组保存在变量中,
  • 每次查看前一个兄弟姐妹时迭代此变量(变量保存排序后的数组很重要)
  • 。如果其年/月不等于当前元素,则编写适当的标题

3) 忘记 XSLT,使用真正的编程语言。

You can't do month_counter++ in XSLT, it's not a procedural language and it's not how XSLT works. So, it's kind of pointless to worry about this being inefficient if this does not work this way.

This looks like a major pain in the neck in XSLT. My XSLT is not fresh enough to try and actually implement it. But here are two ways:

1)

  • use xsl:key to extract all unique years-
  • then iterate through these years. For each year do
  • use xsl:key to extract all months
  • For each month do

2) (seems easier, if it works.)

  • sort them by date, save sorted array in variable
  • iterate this variable (it's important that variable holds sorted array)
  • each time look at preceding-sibling. If its year/month not equal to the current element, write the appropriate header

3) Forget XSLT, use a real programming language.

如此安好 2024-08-18 09:40:21

对于以下解决方案,我使用了此 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>

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

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

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

请参考我对 key() 的解释 在这里。您不需要阅读另一个问题,尽管它是一个类似的问题。请阅读我的答案的下半部分。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文