2012-04-09 112 views

回答

2

您可以通过使用递归模板来做到这一点。这不是最好的解决方案,因为这会受到堆栈溢出或内存不足错误的影响(如果您给它的日期间隔足够大),但它可能是一个开始的地方。

下面的例子需要的第一件事是检查生成的值并确保它是有效的日期(您可以在网上找到一些示例;我只是使用a sample from an open source project并在该示例中仅导入了该文件保持较短)。

然后,我们的想法是通过将一天添加到前一天,然后将一天添加到当前日期来生成日期。如果这一天溢出,您将在月份中添加一个,并从第1天开始重新开始。如果月份溢出,您将与年份相同,并从第1个月开始。理论上,唯一永不会溢出的是年份(但您会限制与间隔的最终值)。

您生成日期并验证它。如果它是有效的并且尚未达到间隔的结束时间,则尝试通过向其添加日期来生成另一个日期(这就是块X中发生的情况)。

当你得到一个无效的值,然后溢出。它只能是一天或一个月(如上所述)。我首先检查月份(方块Y)。如果是这样,我从第一个月的第一天开始,但是第二年开始。如果是溢出的那一天(块Z),那么我从下个月的第一天开始。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:import href="http://www.getsymphony.com/download/xslt-utilities/source-code/54294/"/> 
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" /> 

    <xsl:variable name="startDate" select="'03302012'" /> <!-- MMddyyyy format --> 
    <xsl:variable name="endDate" select="'05302012'" /> <!-- MMddyyyy format --> 

    <xsl:template match="/"> 
    <values> 
     <xsl:call-template name="GenerateList"> 
     <xsl:with-param name="day" select="number(substring($startDate, 3, 2))" /> 
     <xsl:with-param name="month" select="number(substring($startDate, 1, 2))" /> 
     <xsl:with-param name="year" select="number(substring($startDate, 5))" /> 
     </xsl:call-template> 
    </values> 
    </xsl:template> 

    <xsl:template name="GenerateList"> 
    <xsl:param name="day" select="1" /> 
    <xsl:param name="month" select="1" /> 
    <xsl:param name="year" select="1" /> 

    <!-- 1 = valid, 0 = invalid according to the imported file --> 
    <xsl:variable name="validationResult"> 
     <xsl:call-template name="date-is-valid"> 
     <xsl:with-param name="day" select="$day"/> 
     <xsl:with-param name="month" select="$month"/> 
     <xsl:with-param name="year" select="$year"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:choose> 
     <xsl:when test="$validationResult = 0"> 

     <xsl:choose> 
      <xsl:when test="$month &gt; 12"> 
      <!-- block Y --> 
      <xsl:call-template name="GenerateList"> 
       <xsl:with-param name="day" select="1" /> 
       <xsl:with-param name="month" select="1" /> 
       <xsl:with-param name="year" select="$year + 1" /> 
      </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
      <!-- block Z --> 
      <xsl:call-template name="GenerateList"> 
       <xsl:with-param name="day" select="1" /> 
       <xsl:with-param name="month" select="$month + 1" /> 
       <xsl:with-param name="year" select="$year" /> 
      </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 

     </xsl:when> 
     <xsl:otherwise> 
     <!-- block X --> 
     <!-- same MMddyyyy format as the interval values --> 
     <xsl:variable name="currentDate" select="concat(format-number($month, '00'), format-number($day, '00'), $year)" /> 
     <value> 
      <xsl:value-of select="$currentDate" /> 
     </value> 
     <xsl:if test="not($currentDate = $endDate)"> 
      <xsl:call-template name="GenerateList"> 
      <xsl:with-param name="day" select="$day + 1" /> 
      <xsl:with-param name="month" select="$month" /> 
      <xsl:with-param name="year" select="$year" /> 
      </xsl:call-template> 
     </xsl:if> 

     </xsl:otherwise> 
    </xsl:choose> 

    </xsl:template> 
</xsl:stylesheet> 
+0

谢谢你,波格丹!这很酷,适合我! – 2012-04-27 09:11:45

0

不幸的是,XSLT 1.0本身并不适合这样的任务,但其环境通常是这样的。下面是一些方法我用自己:

  1. 最简单的解决方案通常是做出这样的列表中的输入的一部分=)

  2. XSLT转换通常是与特定一个较大的应用程序的一部分XSLT处理器,它允许使用特定手段来扩展。你可以编写一个扩展函数(使用Java,Javascript,PHP,Python取决于处理器),它返回所需的节点集。另一个但类似的选择是注册一个“流”(至少PHP),并使用document函数获取节点集,其中url为app://Dates/listdates?start=a&end=b。缺点是样式表与应用程序耦合,无法单独开发。

  3. 大多数XSTL处理器都支持EXSLT扩展。您可以使用日期扩展来计算日期之间的天数,使用字符串扩展中的padding函数生成一个字符串长度,将字符串拆分为空字符串以获取(需要的长度的)标记列表并迭代列表使用node-set函数并使用date-add将当前节点位置添加到第一个日期。

  4. 按照Bogdan的建议,使用纯XSLT和递归模板。