XSLT 按子节点和位置选择 RSS 项



使用带有 RSS 日历源的 XSLT 1.0,我想排除过期的项目 - 那些在当前日期之前具有 pubDates 的项目 - 然后只包含三个当前项目。结果应该是接下来的三个未来事件。我使用 http://exslt.org/date/index.html 为当前系统日期创建一个变量。问题是,当我选择="item[not(position()> 4)] 和子字符串(item/pubDate,5,11)>= $current"时,如果第一个项目中的任何一个过期,我最终得到的条目少于三个。显然,我的代码选择了三个项目,然后删除了过期的项目,这不是我想要的。是否可以保存未过期项目的副本,然后选择其中三个?

由于 XSLT 1.0 不提供不等式字符串比较运算符,因此我可能无法看到诸如"30 Oct 2013"之类的值是否大于"2013 年 10 月 29 日",我可以将值格式化为 30102013 并改为29102013,但似乎我仍然试图在选择之前连接频道/项目/pubDate。因此,如果可能的话,知道如何分两个阶段处理 XML/RSS 会有所帮助。

我尝试了几种技术,结果相似:

  <xsl:for-each select="substring(item/pubDate,5,11) &gt;= $current and item[not(position() &gt; 4)]">
  <xsl:template match="item[not(position() &gt; 4)]">
       <xsl:apply-templates select="item"/>
  <xsl:for-each select="substring(item/pubDate,5,11) &gt;= $current">
       <xsl:if test=" item[not(position() &gt; 4)]">

示例 XML:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <atom:link href="http://calendar.example.edu/" rel="self" type="application/rss+xml"/>
    <title>University Calendar - Featured Events</title>
    <link>http://calendar.example.edu/</link>
    <description>List of featured events on calendar.example.edu</description>
    <language>en-us</language>
    <pubDate>Tue, 27 Oct 2013 20:47:05 CDT</pubDate>
    <item>
        <title>Creative Movement Program Student Show</title>
        <description/>
        <link>http://calendar.example.edu/?&amp;y=2013&amp;m=10&amp;d=30&amp;eventdatetime_id=19721</link>
        <guid>calendar.example.edu/?&amp;y=2013&amp;m=10&amp;d=30&amp;eventdatetime_id=19721</guid>
        <pubDate>Wed 30 Oct 2013, 17:00:00 CDT</pubDate>
    </item>
    <item>
        <title>Philosophy Career Fair</title>
        <description>The Department of Philosophy brings recruiters from around the state to interview seniors and alumni.</description>
        <link>http://calendar.example.edu/?&amp;y=2013&amp;m=11&amp;d=04&amp;eventdatetime_id=16427</link>
        <guid>calendar.example.edu/?&amp;y=2013&amp;m=11&amp;d=04&amp;eventdatetime_id=16427</guid>
        <pubDate>Mon 04 Nov 2013, 07:00:00 CDT</pubDate>
    </item>
    <item>
        <title>Football vs. Caltech</title>
        <description/>
        <link>http://calendar.example.edu/?&amp;y=2013&amp;m=12&amp;d=07&amp;eventdatetime_id=16521</link>
        <guid>calendar.example.edu/?&amp;y=2013&amp;m=12&amp;d=07&amp;eventdatetime_id=16521</guid>
        <pubDate>Sat 07 Dec 2013, 00:00:00 CDT</pubDate>
    </item>
    <item>
        <title>Mural Exhibition</title>
        <description>The College of Arts presents an overview of wall paintings from the Caves of Lascaux to the Kiev train station.</description>
        <link>http://calendar.example.edu/?&amp;y=2014&amp;m=01&amp;d=14&amp;eventdatetime_id=16759</link>
        <guid>calendar.example.edu/?&amp;y=2014&amp;m=01&amp;d=14&amp;eventdatetime_id=16759</guid>
        <pubDate>Tue 14 Jan 2014, 07:00:00 CDT</pubDate>
    </item>
  </channel>
</rss>

当前 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="date" version="1.0" xmlns:date="http://exslt.org/dates-and-times" >
<xsl:template name="lf">
    <xsl:text/>
</xsl:template>
<xsl:template match="rss">
    <section id="campusEvents" role="region">
        <h2 id="eventsTitle">
            <a href="http://calendar.test.edu/">Campus Events</a>
        </h2>
       <xsl:apply-templates select="channel"/>
        <div class="moreLink">
            <a href="http://calendar.test.edu/">Full Calendar</a>
        </div>
    </section>
</xsl:template>
<xsl:template match="channel">
        <xsl:variable name="currDay" select="substring(date:date(),9,2)"/>
        <xsl:variable name="currMonth">
            <xsl:call-template name="format-month">
                <xsl:with-param name="date" select="date:date()"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="currYear" select="substring(date:date(),1,4)"/>
        <xsl:variable name="current" select="concat($currDay,' ',$currMonth,' ',$currYear )"/>
  <xsl:for-each select="item[not(position() &gt; 4)] and substring(item/pubDate,5,11) &gt;= $current">
        <div class="eventBlock">
            <xsl:call-template name="lf"/>
            <div class="dateBlock">
                <xsl:call-template name="lf"/>
                <div class="eventMonth">
                    <xsl:value-of select="substring(pubDate,8,3)"/>
                </div>
                <div class="eventDate">
                    <xsl:value-of select="substring(pubDate,5,2)"/>
                </div>
            </div>
            <xsl:call-template name="lf"/>
            <div class="eventDescription">
                <a class="url" href="{link}">
                <xsl:value-of select="title"/>
                </a>
                <xsl:call-template name="lf"/>
            </div>
            <xsl:call-template name="lf"/>
        </div>
        <xsl:call-template name="lf"/>
        </xsl:for-each>
</xsl:template>
   <xsl:template name="format-month">
    <xsl:param name="date"/>
    <xsl:variable name="monthName" select="substring(date:date(),6,2)"/>
    <xsl:variable name="month">
        <xsl:choose>
            <xsl:when test="$monthName = '01'">Jan</xsl:when>
            <xsl:when test="$monthName = '02'">Feb</xsl:when>
            <xsl:when test="$monthName = '03'">Mar</xsl:when>
            <xsl:when test="$monthName = '04'">Apr</xsl:when>
            <xsl:when test="$monthName = '05'">May</xsl:when>
            <xsl:when test="$monthName = '06'">Jun</xsl:when>
            <xsl:when test="$monthName = '07'">Jul</xsl:when>
            <xsl:when test="$monthName = '08'">Aug</xsl:when>
            <xsl:when test="$monthName = '09'">Sep</xsl:when>
            <xsl:when test="$monthName = '10'">Oct</xsl:when>
            <xsl:when test="$monthName = '11'">Nov</xsl:when>
            <xsl:when test="$monthName = '12'">Dec</xsl:when>
            <xsl:otherwise/>
        </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="$month"/>
</xsl:template>
</xsl:stylesheet>

期望结果(10 月 30 日活动到期后):

<section role="region" id="campusEvents">
  <h2 id="eventsTitle">
    <a href="http://calendar.test.edu/">Campus Events</a>
  </h2>
 <div class="eventBlock">
    <div class="dateBlock">
        <div class="eventMonth">Nov</div>
        <div class="eventDate">04</div>
    </div>
    <div class="eventDescription">
        <a href="http://calendar.example.edu/?&amp;y=2013&amp;m=11&amp;d=04&amp;eventdatetime_id=16427" class="url">Philosophy Career Fair</a>
    </div>
</div>
  <div class="eventBlock">
    <div class="dateBlock">
        <div class="eventMonth">Dec</div>
        <div class="eventDate">07</div>
    </div>
    <div class="eventDescription">
        <a href="http://calendar.example.edu/?&amp;y=2013&amp;m=12&amp;d=07&amp;eventdatetime_id=16521" class="url">Football vs. Caltech</a>
    </div>
  </div>
  <div class="eventBlock">
    <div class="dateBlock">
        <div class="eventMonth">Jan</div>
        <div class="eventDate">14</div>
    </div>
    <div class="eventDescription">
        <a href="http://calendar.example.edu/?&amp;y=2014&amp;m=01&amp;d=14&amp;eventdatetime_id=16759" class="url">Mural Exhibition</a>
    </div>
  </div>
  <div class="moreLink">
    <a href="http://calendar.test.edu/">Full Calendar</a>
  </div>
</section>

如果你想比较日期,那么你必须以某种方式将各种日期表达式调整为全数字yyyymmdd格式(例如20131029),以便时间顺序等效于数字排序。 对于当前日期,这是一个简单的全局变量:

<xsl:variable name="curDateStr" select="date:date()" />
<xsl:variable name="currentDateNum"
   select="concat(substring($curDateStr, 1, 4),
                  substring($curDateStr, 6, 2),
                  substring($curDateStr, 9, 2))" />

为了解析pubDate值,我会使用与您当前format-month相反的命名模板

<xsl:template name="parse-date">
  <xsl:param name="dateStr" />
  <xsl:value-of select="substring($dateStr, 12, 4)" /><!-- year -->
  <xsl:variable name="month" select="substring($dateStr, 8, 3)" />
  <xsl:choose>
    <xsl:when test="$month = 'Jan'">01</xsl:when>
    <xsl:when test="$month = 'Feb'">02</xsl:when>
    <!-- etc. -->
  </xsl:choose>
  <xsl:value-of select="substring($dateStr, 5, 2)" /><!-- day -->
</xsl:template>

现在,可以使用尾递归模板实现主要逻辑,该模板是XSLT中最接近"while"循环

的模板:
<xsl:template match="item">
  <xsl:param name="numItems" select="3" />
  <xsl:if test="$numItems &gt; 0"><!-- stop if we hit the threshold -->
    <xsl:variable name="itemDate">
      <xsl:call-template name="parse-date">
        <xsl:with-param name="dateStr" select="pubDate" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
     <xsl:when test="$itemDate &gt; $currentDateNum">
        <!-- do what you need to do to produce output for this item -->
        <!-- ..... -->
        <xsl:apply-templates select="following-sibling::item[1]">
          <!-- we processed this item, so decrement $numItems -->
          <xsl:with-param name="numItems" select="$numItems - 1" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="following-sibling::item[1]">
          <!-- we ignored this item, so don't decrement $numItems -->
          <xsl:with-param name="numItems" select="$numItems" />
        </xsl:apply-templates>
      </xsl:otherwise>
    </xsl:choose>
  <xsl:if>
</xsl:template>

然后在channel模板中,您可以通过仅将模板应用于第一项来启动此"循环"

<xsl:template match="channel">
  <xsl:apply-templates select="item[1]" />
</xsl:template>

然后,项模板将继续处理同级元素,直到它完全用完item元素,或者它处理了 3 个符合日期条件的项目。

相关内容

  • 没有找到相关文章

最新更新