1

I am trying to create XSLT that will take two dates from my XML output and give me the difference between the two days without weekends included. I found this code below from another user

(How to get only business days between two dates in xslt 1.0)

But I am having trouble calling my xml properly. Any advice on how to get the below code to reference my xml?

EDIT: Upon further research it seems I cannot select an attribute on a function parameter. Any other Ideas would be appreciated.

XML Sample and XSLT below:

<?xml version="1.0" encoding="UTF-8"?>

<Report_Data xmlns="urn:examplenamespace.com">
    <Report_Entry>
        <LOACalcStart>2022-01-09</wd:LOACalcStart>
        <LOACalcEnd>2022-04-21</wd:LOACalcEnd>
    </Report_Entry>
    <Report_Entry>
        <LOACalcStart>2022-01-21</wd:LOACalcStart>
        <LOACalcEnd>2022-04-22</wd:LOACalcEnd>
    </Report_Entry>
</Report_Data>

 <xsl:template match="/">
    <xsl:value-of select="this:WorkDayDifference(xs:date('2014-05-01'),xs:date('2014-05-12'))"/>
    

</xsl:template>

    <xsl:function name="this:WorkDayDifference">
        <xsl:param name="startDate" as="xs:date"/>
        <xsl:param name="endDate" as="xs:date"/>
        <xsl:variable name="endDateDay" select="this:day-of-week($endDate)"/>
        <xsl:variable name="days" select="days-from-duration($endDate - $startDate)"/>
        <xsl:variable name="dow1" select="this:day-of-week($startDate)"/>
        <xsl:variable name="dow2" select="this:day-of-week($endDate)"/>
        <xsl:variable name="weeks" select="xs:integer($days div 7)"/>
        <xsl:variable name="offset" select="if($dow2 ge $dow1) then if($endDateDay = 6 or $endDateDay = 0)then(-6)else(-5) else if($endDateDay = 6 or $endDateDay = 0)then(-1)else(0)"/>
        <xsl:variable name="wdays" select="sum((0,1,1,1,1,1,0,0,1,1,1,1,1,0)[position() ge $dow1 + 1 and position() le ($dow2 + 7)]) + $weeks * 5 + $offset + 1"/>
        <xsl:value-of select="number($wdays)"/>
    </xsl:function>
    
    <xsl:function name="this:day-of-week" as="xs:integer?" >
        <xsl:param name="date" as="xs:anyAtomicType?"/>
        <xsl:sequence select="if (empty($date)) then () else (xs:integer((xs:date($date) - xs:date('1901-01-06')) div xs:dayTimeDuration('P1D')) mod 7)"/>
    </xsl:function> ```

1 Answers1

2

Just invoke the function as

<xsl:template match="/" xpath-default-namespace="urn:examplenamespace.com">
    <xsl:value-of select="this:WorkDayDifference(
            xs:date(//StartDate), xs:date(//EndDate))"/>
</xsl:template>

I can't help feeling that there must be a more elegant implementation of this:workDayDifference(), but nothing comes immediately to mind.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Good Morning @MichaelKay . I made the mistake yesterday of not including an XML sample with multiple records. I am now getting this error " [Saxon-P.E 9.9.1.7.] A sequence of more than one item is not allowed as the value in 'cast as' expression (, ). I will edit my original post to post the proper Sample Xml . – XSLT_apprentice May 09 '22 at 14:16
  • 1
    If you've got multiple start-date/end-date pairs then you obviously need to call the function once for each such pair. (I think you're asking questions here when you should be using a textbook or tutorial to learn the basics of the language). – Michael Kay May 09 '22 at 14:24
  • For each worked, was just a syntax error. Thanks again. – XSLT_apprentice May 09 '22 at 15:25