使用 XSLT 比较日期周期

发布于 2024-08-17 05:41:54 字数 1079 浏览 7 评论 0原文

我对 XSLT 有一些经验,但现在我遇到了一个问题: 我需要检查开始日期和结束日期之间的时间段是否完全覆盖其他时间段。

这是 xml 的一部分:

<Parent ID="1">
  <StartDate>20050101</StartDate>
  <EndDate>20060131</EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>
<Parent ID="2">
  <StartDate>20060201</StartDate>
  <EndDate>20071231</EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>
<Parent ID="3">
  <StartDate>20080101</StartDate>
  <EndDate>20081231<EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>

因此,我需要检查 XSLT 中父项的开始和结束之间的时间段是否完全被子项的开始和结束之间的时间段覆盖,并将父项和子项 ID 写入 xml,以防止失败。

有人可以告诉我如何在 XSLT 中管理这个......?

我可以完全控制 XML 的结构,因此当使用其他 XML 结构(具有相同的数据)更容易时,我可以更改它。

多谢!

I have some experience with XSLT but now i've got myself a problem:
I need to check if a period between a begin- and enddate completely covers an other period.

Here's a part of the xml:

<Parent ID="1">
  <StartDate>20050101</StartDate>
  <EndDate>20060131</EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>
<Parent ID="2">
  <StartDate>20060201</StartDate>
  <EndDate>20071231</EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>
<Parent ID="3">
  <StartDate>20080101</StartDate>
  <EndDate>20081231<EndDate>
  <Child ID="1">
    <StartDate>20050101</StartDate>
    <EndDate>20081231</EndDate>
  </Child>
</Parent>

So i need to check if the period between start and end of the Parent is fully covered by the period between start and end of the Child in XSLT and write the Parent and Child ID's to xml for fails.

Can someone give me a head start how to manage this in XSLT...?

I have full control over the structure of the XML so when it's easier with an other XML structure (with the same data) i can change it.

Thanks a lot!

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

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

发布评论

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

评论(4

君勿笑 2024-08-24 05:41:54

下面是一个直接在 xslt 2.0 中执行此操作的示例,并且应该适用于大多数日期分隔符:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
            exclude-result-prefixes="functx xs"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:functx="http://www.functx.com"
            xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <xsl:template match="/">
            <dates>
                <dateBetween>
                    <xsl:choose>
                        <xsl:when test="functx:dateBetween('02-01-2009','01-01-2009','03-01-2009')=true()">
                            <xsl:text>date lays between given dates</xsl:text>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>date is not between given dates</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </dateBetween>
                <currentDateBetween>
                    <xsl:choose>
                        <xsl:when test="functx:currentDateBetween('01-01-2000','01-01-2019')=true()">
                            <xsl:text>current date lays between given dates</xsl:text>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>current date is not between given dates</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </currentDateBetween>
            </dates>
        </xsl:template>

         <!-- 
            Function:       dateBetween
            Description:    This function will check if a dates is between given dates
            Input:          Input date, Input start date, Input end date
            Output:         Boolean true if beween param 2 and 3
            Created:        21-09-2012 by Raymond Meester
        -->
        <xsl:function name="functx:dateBetween">
            <xsl:param name="param1"/>
            <xsl:param name="param2"/>
            <xsl:param name="param3"/>

            <xsl:variable name ="dateToCheck" select="functx:mmddyyyy-to-date($param1)"/>        
            <xsl:variable name ="startDate" select="functx:mmddyyyy-to-date($param2)"/>
            <xsl:variable name ="endDate" select="functx:mmddyyyy-to-date($param3)"/>    
            <xsl:variable name ="true" as="xs:boolean" select="true()"/>
            <xsl:variable name ="false" as="xs:boolean" select="false()"/>          

            <xsl:choose>
                <xsl:when test="$startDate < $dateToCheck and $dateToCheck < $endDate"><xsl:value-of select="$true"/></xsl:when>
                <xsl:otherwise><xsl:value-of select="$false"/></xsl:otherwise>
            </xsl:choose>

        </xsl:function>

        <!-- 
            Function:       currentDateBetween
            Description:    This function will check if a dates is between given dates
            Input:          Input date, Input start date, Input end date
            Output:         Boolean true if beween param 2 and 3
            Created:        21-09-2012 by Raymond Meester
        -->    
        <xsl:function name="functx:currentDateBetween">
            <xsl:param name="param1"/>
            <xsl:param name="param2"/>

            <xsl:variable name ="startDate" select="functx:mmddyyyy-to-date($param1)"/>
            <xsl:variable name ="endDate" select="functx:mmddyyyy-to-date($param2)"/>    
            <xsl:variable name ="true" as="xs:boolean" select="true()"/>
            <xsl:variable name ="false" as="xs:boolean" select="false()"/>          

            <xsl:choose>
                <xsl:when test="$startDate < current-date() and current-date() < $endDate"><xsl:value-of select="$true"/></xsl:when>
                <xsl:otherwise><xsl:value-of select="$false"/></xsl:otherwise>
            </xsl:choose>

        </xsl:function>

        <!-- 
            Function:       mmddyyyy-to-date
            Description:    The functx:mmddyyyy-to-date function converts $dateString into a valid xs:date value. The order of the digits in $dateString must be MMDDYYYY, but it can contain any (or no) delimiters between the digits.
            Input:          Input string
            Output:         Return date
            Created:        2007-02-26 http://www.xsltfunctions.com/xsl/functx_mmddyyyy-to-date.html
        -->      
        <xsl:function name="functx:mmddyyyy-to-date" as="xs:date?"
                xmlns:functx="http://www.functx.com">
            <xsl:param name="dateString" as="xs:string?"/>
            <xsl:sequence select="if (empty($dateString)) then () else if (not(matches($dateString,'^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*
))) then error(xs:QName('functx:Invalid_Date_Format')) else xs:date(replace($dateString,'^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*
,'$3-$1-$2'))"/>
        </xsl:function>

    </xsl:stylesheet>

Here is an example to do it directly in xslt 2.0 and should work with most date delimeters:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
            exclude-result-prefixes="functx xs"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:functx="http://www.functx.com"
            xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <xsl:template match="/">
            <dates>
                <dateBetween>
                    <xsl:choose>
                        <xsl:when test="functx:dateBetween('02-01-2009','01-01-2009','03-01-2009')=true()">
                            <xsl:text>date lays between given dates</xsl:text>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>date is not between given dates</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </dateBetween>
                <currentDateBetween>
                    <xsl:choose>
                        <xsl:when test="functx:currentDateBetween('01-01-2000','01-01-2019')=true()">
                            <xsl:text>current date lays between given dates</xsl:text>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>current date is not between given dates</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </currentDateBetween>
            </dates>
        </xsl:template>

         <!-- 
            Function:       dateBetween
            Description:    This function will check if a dates is between given dates
            Input:          Input date, Input start date, Input end date
            Output:         Boolean true if beween param 2 and 3
            Created:        21-09-2012 by Raymond Meester
        -->
        <xsl:function name="functx:dateBetween">
            <xsl:param name="param1"/>
            <xsl:param name="param2"/>
            <xsl:param name="param3"/>

            <xsl:variable name ="dateToCheck" select="functx:mmddyyyy-to-date($param1)"/>        
            <xsl:variable name ="startDate" select="functx:mmddyyyy-to-date($param2)"/>
            <xsl:variable name ="endDate" select="functx:mmddyyyy-to-date($param3)"/>    
            <xsl:variable name ="true" as="xs:boolean" select="true()"/>
            <xsl:variable name ="false" as="xs:boolean" select="false()"/>          

            <xsl:choose>
                <xsl:when test="$startDate < $dateToCheck and $dateToCheck < $endDate"><xsl:value-of select="$true"/></xsl:when>
                <xsl:otherwise><xsl:value-of select="$false"/></xsl:otherwise>
            </xsl:choose>

        </xsl:function>

        <!-- 
            Function:       currentDateBetween
            Description:    This function will check if a dates is between given dates
            Input:          Input date, Input start date, Input end date
            Output:         Boolean true if beween param 2 and 3
            Created:        21-09-2012 by Raymond Meester
        -->    
        <xsl:function name="functx:currentDateBetween">
            <xsl:param name="param1"/>
            <xsl:param name="param2"/>

            <xsl:variable name ="startDate" select="functx:mmddyyyy-to-date($param1)"/>
            <xsl:variable name ="endDate" select="functx:mmddyyyy-to-date($param2)"/>    
            <xsl:variable name ="true" as="xs:boolean" select="true()"/>
            <xsl:variable name ="false" as="xs:boolean" select="false()"/>          

            <xsl:choose>
                <xsl:when test="$startDate < current-date() and current-date() < $endDate"><xsl:value-of select="$true"/></xsl:when>
                <xsl:otherwise><xsl:value-of select="$false"/></xsl:otherwise>
            </xsl:choose>

        </xsl:function>

        <!-- 
            Function:       mmddyyyy-to-date
            Description:    The functx:mmddyyyy-to-date function converts $dateString into a valid xs:date value. The order of the digits in $dateString must be MMDDYYYY, but it can contain any (or no) delimiters between the digits.
            Input:          Input string
            Output:         Return date
            Created:        2007-02-26 http://www.xsltfunctions.com/xsl/functx_mmddyyyy-to-date.html
        -->      
        <xsl:function name="functx:mmddyyyy-to-date" as="xs:date?"
                xmlns:functx="http://www.functx.com">
            <xsl:param name="dateString" as="xs:string?"/>
            <xsl:sequence select="if (empty($dateString)) then () else if (not(matches($dateString,'^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*
))) then error(xs:QName('functx:Invalid_Date_Format')) else xs:date(replace($dateString,'^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*
,'$3-$1-$2'))"/>
        </xsl:function>

    </xsl:stylesheet>
黑色毁心梦 2024-08-24 05:41:54

使用简单的字符串比较这很容易,因为您的日期格式是大尾数。下面是我为了测试它而编写的一个快速 XSLT 文档:

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

  <xsl:template match="/">
    <root>
      <xsl:for-each select="//Parent">
        <parent>
          <xsl:attribute name="id">
            <xsl:value-of select="@ID"/>
          </xsl:attribute>
          <xsl:choose>
            <xsl:when test="(Child/StartDate <= StartDate) and 
              (Child/EndDate >= EndDate)">
              <xsl:text>OK</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>Not OK</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </parent>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

显然,您需要自己进行检查,以确保父级和子级的 StartDate 早于 EndDate

Using simple string comparison this is easy, because your date format is big-endian. Here's a quick XSLT document I wrote up to test it out:

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

  <xsl:template match="/">
    <root>
      <xsl:for-each select="//Parent">
        <parent>
          <xsl:attribute name="id">
            <xsl:value-of select="@ID"/>
          </xsl:attribute>
          <xsl:choose>
            <xsl:when test="(Child/StartDate <= StartDate) and 
              (Child/EndDate >= EndDate)">
              <xsl:text>OK</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>Not OK</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </parent>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

Obviously you'll need your own checks to make sure that StartDate is before EndDate for both parent and child.

晚风撩人 2024-08-24 05:41:54

number(Child/StartDate) <= number(Parent/StartDate) 和 number(Child/EndDate) >= number(Parent/EndDate) 有什么问题吗?

What's wrong with number(Child/StartDate) <= number(Parent/StartDate) and number(Child/EndDate) >= number(Parent/EndDate)?

挖个坑埋了你 2024-08-24 05:41:54

这并不是一个完整的解决方案,但您可能想查看用于日期操作的 EXSLT 扩展,此处

不过,我会考虑使用 XSLT 扩展函数 创建几个="http://joda-time.sourceforge.net/api-release/org/joda/time/Interval.html" rel="nofollow noreferrer">Joda 时间的 Interval 抽象。可能比直接从 XSLT 尝试更容易、更快。

This is not going to a complete solution, but you may want to check out the EXSLT extensions for date manipulation, here.

I would however consider creating a couple of XSLT extension functions, using Joda time's Interval abstractions. Probably way easier and faster than trying to do it from XSLT directly.

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