How to do a for loop in xslt 1.0 to output a 52 week calendar irrespective of the data - xslt-1.0

I understand some of the limitations of XSLT1.0 with the for-each loop. I need a way of processing a file 52 times so I can allocate an output to each of the 52 weeks of the year. The file is a simple Time Away From Work XML (each node has date / time / code etc...) and I need each week to contain the records of any TAFWs booked for that week, but I must always output 52 sections even if there is no data in the week.
The data will be sorted by date, but I need a way of cycling it round 52 times. It must always be 52 weeks from last week, so it always need to be relative otherwise I would have created a temp xml within the XSLT.
For-each only works if there is more than 52 nodes, so I can't use that as there may not be more than 52 nodes.
RAW Data
<Record>
<emp_number>73001486</emp_number>
<paycode>HOLIDAY</paycode>
<allday_flag>True</allday_flag>
<halfday_flag>False</halfday_flag>
<nethours>96.000</nethours>
<startdate_time>2021-12-14 00:00:00</startdate_time>
<enddate_time>2021-12-16 00:00:00</enddate_time>
</Record>
Output:
2021-12-06
2021-12-13
73001486,HOLIDAY,96
Any ideas gratefully received!
Update: Week start is previous week, which I can derive from passed information. Always full weeks. I don't care about holidays which span weeks, I just care about TAFW start dates within the 52 week periods (which I am comfortable with deducing).

I think your question should be broken into several separate steps - and neither of these is exactly trivial.
The first step would be to generate 52 weeks from a given start date. Well, actually the first step would be to calculate the start date, but at this point I don't know what to use as the input for this, so let's assume it's a given:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<output>
<xsl:call-template name="generate-weeks">
<xsl:with-param name="start-date" select="'2020-11-30'" />
<xsl:with-param name="n" select="52" />
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="generate-weeks">
<xsl:param name="start-date"/>
<xsl:param name="n" select="52"/>
<xsl:if test="$n > 0">
<week start-date="{$start-date}"/>
<xsl:call-template name="generate-weeks">
<xsl:with-param name="start-date">
<xsl:variable name="JDN">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$start-date" />
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="GD">
<xsl:with-param name="JDN" select="$JDN + 7" />
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="JDN">
<xsl:param name="date"/>
<xsl:variable name="year" select="substring($date, 1, 4)"/>
<xsl:variable name="month" select="substring($date, 6, 2)"/>
<xsl:variable name="day" select="substring($date, 9, 2)"/>
<xsl:variable name="a" select="floor((14 - $month) div 12)"/>
<xsl:variable name="y" select="$year + 4800 - $a"/>
<xsl:variable name="m" select="$month + 12*$a - 3"/>
<xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
<xsl:template name="GD">
<xsl:param name="JDN"/>
<xsl:variable name="f" select="$JDN + 1401 + floor((floor((4 * $JDN + 274277) div 146097) * 3) div 4) - 38"/>
<xsl:variable name="e" select="4*$f + 3"/>
<xsl:variable name="g" select="floor(($e mod 1461) div 4)"/>
<xsl:variable name="h" select="5*$g + 2"/>
<xsl:variable name="D" select="floor(($h mod 153) div 5 ) + 1"/>
<xsl:variable name="M" select="(floor($h div 153) + 2) mod 12 + 1"/>
<xsl:variable name="Y" select="floor($e div 1461) - 4716 + floor((14 - $M) div 12)"/>
<xsl:value-of select="$Y" />
<xsl:value-of select="format-number($M, '-00')"/>
<xsl:value-of select="format-number($D, '-00')"/>
</xsl:template>
</xsl:stylesheet>
This will produce:
Result
<?xml version="1.0" encoding="utf-8"?>
<output>
<week start-date="2020-11-30"/>
<week start-date="2020-12-07"/>
<week start-date="2020-12-14"/>
<week start-date="2020-12-21"/>
<week start-date="2020-12-28"/>
<week start-date="2021-01-04"/>
<week start-date="2021-01-11"/>
<week start-date="2021-01-18"/>
<week start-date="2021-01-25"/>
<week start-date="2021-02-01"/>
<week start-date="2021-02-08"/>
<week start-date="2021-02-15"/>
<week start-date="2021-02-22"/>
<week start-date="2021-03-01"/>
<week start-date="2021-03-08"/>
<week start-date="2021-03-15"/>
<week start-date="2021-03-22"/>
<week start-date="2021-03-29"/>
<week start-date="2021-04-05"/>
<week start-date="2021-04-12"/>
<week start-date="2021-04-19"/>
<week start-date="2021-04-26"/>
<week start-date="2021-05-03"/>
<week start-date="2021-05-10"/>
<week start-date="2021-05-17"/>
<week start-date="2021-05-24"/>
<week start-date="2021-05-31"/>
<week start-date="2021-06-07"/>
<week start-date="2021-06-14"/>
<week start-date="2021-06-21"/>
<week start-date="2021-06-28"/>
<week start-date="2021-07-05"/>
<week start-date="2021-07-12"/>
<week start-date="2021-07-19"/>
<week start-date="2021-07-26"/>
<week start-date="2021-08-02"/>
<week start-date="2021-08-09"/>
<week start-date="2021-08-16"/>
<week start-date="2021-08-23"/>
<week start-date="2021-08-30"/>
<week start-date="2021-09-06"/>
<week start-date="2021-09-13"/>
<week start-date="2021-09-20"/>
<week start-date="2021-09-27"/>
<week start-date="2021-10-04"/>
<week start-date="2021-10-11"/>
<week start-date="2021-10-18"/>
<week start-date="2021-10-25"/>
<week start-date="2021-11-01"/>
<week start-date="2021-11-08"/>
<week start-date="2021-11-15"/>
<week start-date="2021-11-22"/>
</output>
The next step would be pre-process the input records and assign each one the value of the starting day of its week. This can be then used to assign each record to the corresponding week by matching the two start-dates. I suggest you ask a separate question (or questions) about that.

Related

Want to sum the key quantities of each line recursively in XSLT

I have done few calculations using key-match for each line and i am expecting to sum the total of these values at the last row.
Below is the calculation.
LINE#1
4 (DispatchQuantity = 2; occurrence = 2 -> 2 x 2 = 4) MID-LAYER 12 (UnitNetWeight = 3KG x 12)
4 (DispatchQuantity = 2; occurrence = 2 -> 2 x 2 = 4) PALLET-LAYER 12 (UnitNetWeight = 3KG x 12)
LINE#2
8 (DispatchQuantity = 4; occurrence = 2 -> 4 x 2 = 8) MID-LAYER 24 (UnitNetWeight = 3KG x 8)
I need to add the numbers of each line to produce one last block which should contains 16 (4+4+8) and 48(12+12+24)
current o/p:
4 MID-LAYER 12
4 PALLET-LAYER 12
8 MID-LAYER 24
XML:
<?xml version="1.0" encoding="UTF-8"?>
<cXML payloadID="16314uu19eii6-765h52u1pp0.162.97.178" timestamp="2021-10-06T02:54:24-07:00" version="1.2.051" xml:lang="en-PL">
<Header>
<Line>
<Items>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>One</Code>
<CodeIdentifier>MID-LAYER</CodeIdentifier>
<DispatchQuantity quantity="2.0"/>
</Item>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>MID-LAYER</CodeIdentifier>
<DispatchQuantity quantity="2.0"/>
</Item>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>MID-LAYER</CodeIdentifier>
<DispatchQuantity quantity="2.0"/>
</Item>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>PALLET-LAYER</CodeIdentifier>
<DispatchQuantity quantity="2.0"/>
</Item>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>PALLET-LAYER</CodeIdentifier>
<DispatchQuantity quantity="2.0"/>
</Item>
</Items>
<Items>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>MID-LAYER</CodeIdentifier>
<DispatchQuantity quantity="4.0"/>
</Item>
<Item>
<Dimension type="unitNetWeight" quantity="3.0"/>
<Code>auxiliary</Code>
<CodeIdentifier>MID-LAYER</CodeIdentifier>
<DispatchQuantity quantity="4.0"/>
</Item>
</Items>
</Line>
</Header>
</cXML>
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="date"
>
<!--unique key-->
<xsl:key name="aux" match="Item[Code='auxiliary']" use="concat(CodeIdentifier, '|', generate-id(..))"/>
<xsl:decimal-format name="generalFormat" grouping-separator="," decimal-separator="." />
<xsl:output method="xml" indent="yes" />
<xsl:template match="/" name="Barcode">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="ManufacturLabelSize-first" page-height="297mm" page-width="210mm" margin-top="25.4mm" margin-right="25.4mm" margin-left="25.4mm" margin-bottom="25.4mm">
<fo:region-body margin-top="15mm" />
<fo:region-before />
<fo:region-after />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="ManufacturLabelSize-first" id="pSeqID">
<fo:flow flow-name="xsl-region-body">
<fo:table>
<fo:table-body border="solid" border-width="0.5pt">
<xsl:for-each select="cXML/Header/Line">
<xsl:for-each select="Items">
<fo:table-row>
<fo:table-cell>
<!--DispatchQuantity*occurence-->
<fo:block>
<xsl:for-each select="Item[Code='auxiliary'][count(. | key('aux', concat(CodeIdentifier, '|', generate-id(..)))[1]) = 1]">
<fo:block >
<xsl:value-of select="(DispatchQuantity/#quantity) * count(key('aux', concat(CodeIdentifier, '|', generate-id(..))))"/>
</fo:block>
</xsl:for-each>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<!--unique code-->
<fo:block>
<xsl:for-each select="Item[Code='auxiliary'][count(. | key('aux', concat(CodeIdentifier, '|', generate-id(..)))[1]) = 1]">
<fo:block >
<xsl:value-of select="CodeIdentifier"/>
</fo:block>
</xsl:for-each>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<!--(DispatchQuantity*occurence)*UnitNetWeight-->
<fo:block>
<xsl:for-each select="Item[Code='auxiliary'][count(. | key('aux', concat(CodeIdentifier, '|', generate-id(..)))[1]) = 1]">
<fo:block font-size="8" font-family="Calibri" padding-before="2mm" start-indent="0.75mm">
<xsl:value-of select="(DispatchQuantity/#quantity) * count(key('aux', concat(CodeIdentifier, '|', generate-id(..)))) * Dimension[#type='unitNetWeight']/#quantity"/>
</fo:block>
</xsl:for-each>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
Your kind help is much valued!
Consider this simplified example:
XSLT 1.0 (+EXSLT node-set() function)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="aux" match="Item[Code='auxiliary']" use="concat(CodeIdentifier, '|', generate-id(..))"/>
<xsl:template match="cXML">
<xsl:variable name="groups-RTF">
<xsl:for-each select="//Item[Code='auxiliary'][count(. | key('aux', concat(CodeIdentifier, '|', generate-id(..)))[1]) = 1]">
<group code="{CodeIdentifier}">
<xsl:variable name="group-size" select="count(key('aux', concat(CodeIdentifier, '|', generate-id(..))))"/>
<xsl:variable name="quantity" select="DispatchQuantity/#quantity * $group-size"/>
<quantity>
<xsl:value-of select="$quantity"/>
</quantity>
<weight>
<xsl:value-of select="Dimension[#type='unitNetWeight']/#quantity * $quantity"/>
</weight>
</group>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="groups" select="exsl:node-set($groups-RTF)/group" />
<!-- output -->
<xsl:text>code, quantity, weight
</xsl:text>
<xsl:for-each select="$groups">
<xsl:value-of select="#code"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="quantity"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="weight"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>TOTAL, </xsl:text>
<xsl:value-of select="sum($groups/quantity)"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="sum($groups/weight)"/>
</xsl:template>
</xsl:stylesheet>
Result
code, quantity, weight
MID-LAYER, 4, 12
PALLET-LAYER, 4, 12
MID-LAYER, 8, 24
TOTAL, 16, 48

Get enum value from string using xslt and xsd

I am trying to get the enum value of the corresponding string. I am translating one XML into another.
For example, the source element is
<VehicleBodyType>Van</VehicleBodyType>
I need to transform it to
<VehicleTypeCode>5</VehicleTypeCode>
This is in an XSD:
<xs:simpleType name="VehicleBodyType">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="NotApplicable" />
<xs:enumeration value="PassengerCar" />
<xs:enumeration value="TruckPickupOrPassengerTruck" />
<xs:enumeration value="Van" />
<xs:enumeration value="TruckSingleUnitTruck2Axles" />
<xs:enumeration value="MotorHomeRecreationalVehicle" />
</xs:restriction>
</xs:simpleType>
I tried this:
<VehicleTypeCode>
<xsl:template match="xs:simpleType[#name='VehicleBodyType']/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>
</VehicleTypeCode>
but would get an error indicating that I can't do a template as a child of 'VehicleTypeCode' element.
I would prefer to use an XSD, but I can put this into the XSLT as well, if that makes it easier. I don't even know if the for-each is valid, but I found it on here and it looks like what I want.
Here is a sample of the source xml:
<?xml version="1.0" encoding="UTF-8"?>
<Crash>
<Vehicles>
<Vehicle>
<VehicleBodyType>Van</VehicleBodyType>
<VehicleColor>Red</VehicleColor>
</Vehicle>
</Vehicles>
</Crash>
Here the stripped down xslt i'm using:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" exclude-result-prefixes="xsl xs fn xsi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Crash" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CrashEntity>
<WorkZoneWorkers>
<xsl:value-of select="WorkersPresentCde"/>
</WorkZoneWorkers>
<xsl:choose>
<xsl:when test="not(Vehicles/Vehicle)">
<CrashUnits/>
</xsl:when>
<xsl:otherwise>
<CrashUnits>
<xsl:apply-templates select="Vehicles/Vehicle" />
</CrashUnits>
</xsl:otherwise>
</xsl:choose>
</CrashEntity>
</xsl:template>
<!-- Vehicles/Vehicle -->
<xsl:template match="Vehicles/Vehicle">
<CrashUnitsEntity>
<VehicleTypeCode>
<xsl:value-of select="VehicleBodyType"/>
</VehicleTypeCode>
<!--Can't use a template within a template-->
<!--<xsl:template match="xs:simpleType[#name='VehicleBodyType']/xs:restriction">
<VehicleTypeCode>
<xsl:value-of select="count(xs:enumeration[#value = 'Van']/preceding-sibling::xs:enumeration) + 1"/>
</VehicleTypeCode>
</xsl:template>-->
<!--Can't use a template within a template (original attempt)-->
<!--<VehicleTypeCode>
<xsl:template match="xs:simpleType[#name=$data]/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>
</VehicleTypeCode>-->
<!--Try to call a function-->
<VehicleTypeCode function="Enum1">
<xsl:call-template name="getEnum1">
<xsl:with-param name="type" select="VehicleBodyType"/>
<xsl:with-param name="data" select="VehicleBodyType"/>
</xsl:call-template>
</VehicleTypeCode>
<!--Try to call a function-->
<VehicleTypeCode function="Enum2">
<xsl:call-template name="getEnum2">
<xsl:with-param name="type" select="VehicleBodyType"/>
<xsl:with-param name="data" select="VehicleBodyType"/>
</xsl:call-template>
</VehicleTypeCode>
<Vehicle>
<UnitNumber>
<xsl:value-of select="#VehicleNumber"/>
</UnitNumber>
</Vehicle>
</CrashUnitsEntity>
</xsl:template>
<!-- ##################################### functions ##################################### -->
<!-- Can't call a template inside another template-->
<xsl:template name="getEnum1">
<xsl:param name="type"/>
<xsl:param name="data"/>
<xsl:if test="$data">
<!--<xsl:template match="xs:simpleType[#name=$type]/xs:restriction">
<xsl:for-each select="xs:enumeration">
<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>-->
</xsl:if>
</xsl:template>
<!-- Can't call a template inside another template-->
<xsl:template name="getEnum2">
<xsl:param name="type"/>
<xsl:param name="data"/>
<xsl:if test="$data">
<!--<xsl:template match="xs:simpleType[#name=$type]/xs:restriction">
<xsl:value-of select="count(xs:enumeration[#value = $data]/preceding-sibling::xs:enumeration) + 1"/>
</xsl:template>-->
</xsl:if>
</xsl:template>
<xs:simpleType name="VehicleBodyType">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="NotApplicable" />
<xs:enumeration value="PassengerCar" />
<xs:enumeration value="Van" />
<xs:enumeration value="Truck" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="VehicleColor">
<xs:restriction base="xs:string">
<xs:enumeration value="NotProvided" />
<xs:enumeration value="Red" />
<xs:enumeration value="Green" />
<xs:enumeration value="Blue" />
</xs:restriction>
</xs:simpleType>
</xsl:stylesheet>
Expected output xml:
<?xml version="1.0" encoding="UTF-8"?>
<CrashEntity>
<WorkZoneWorkers/>
<CrashUnits>
<CrashUnitsEntity>
<VehicleTypeCode>4</VehicleTypeCode>
<VehicleColor>2</VehicleColor>
</CrashUnitsEntity>
</CrashUnits>
</CrashEntity>

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

I need help to count only business days (i.e excluding Saturday and Sunday ) between two dates in xslt 1.0
count only business days (i.e excluding Saturday and Sunday ) between
two dates in xslt 1.0
If it can be assumed that the two given dates will not fall on Saturday or Sunday, you could use the method shown in the following example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<output>
<workdays>
<xsl:call-template name="duration-in-workdays">
<xsl:with-param name="start-date" select="'2015-04-02'" />
<xsl:with-param name="end-date" select="'2015-04-08'" />
</xsl:call-template>
</workdays>
</output>
</xsl:template>
<xsl:template name="duration-in-workdays">
<!-- assumes start-date and end-date are both workdays -->
<xsl:param name="start-date"/>
<xsl:param name="end-date"/>
<xsl:variable name="start">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$start-date" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="end">
<xsl:call-template name="JDN">
<xsl:with-param name="date" select="$end-date" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="start-weekday" select="($start + 1) mod 7" />
<xsl:variable name="end-weekday" select="($end + 1) mod 7" />
<xsl:variable name="weeks" select="floor(($end - $start) div 7)" />
<xsl:variable name="days" select="($end - $start) mod 7" />
<xsl:value-of select="5 * $weeks + $days - 2*($start-weekday > $end-weekday)"/>
</xsl:template>
<xsl:template name="JDN">
<xsl:param name="date"/>
<xsl:variable name="year" select="substring($date, 1, 4)"/>
<xsl:variable name="month" select="substring($date, 6, 2)"/>
<xsl:variable name="day" select="substring($date, 9, 2)"/>
<xsl:variable name="a" select="floor((14 - $month) div 12)"/>
<xsl:variable name="y" select="$year + 4800 - $a"/>
<xsl:variable name="m" select="$month + 12*$a - 3"/>
<xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
</xsl:stylesheet>
</xsl:stylesheet>
Caveat: not tested thoroughly.
<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>

XSLT 1.0 Substring from right side of string

I have a value in an element as 433554567643.
I would like to change it to 43 35545 67643. The grouping should start from right side of the value.
Is it possible to use subtring from end to start of the value?
Thanks.
You could do this with a recursive template.
<xsl:template name="add-spaces">
<xsl:param name="group" select="5" />
<xsl:param name="text" />
<xsl:if test="string-length($text) > $group">
<xsl:call-template name="add-spaces">
<xsl:with-param name="group" select="$group" />
<xsl:with-param name="text"
select="substring($text, 1, string-length($text) - $group)" />
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="substring($text, string-length($text) - $group + 1)" />
</xsl:template>
You would call this when required using
<xsl:call-template name="add-spaces">
<xsl:with-param name="text" select="'433554567643'" />
<!-- or select="path/to/element" as appropriate -->
</xsl:call-template>
If your value is always a number, you could use format-number() with a pattern that groups the numbers by 5 digits and then translate() the "," into " ":
<xsl:value-of select="translate(format-number('433554567643', '#,#####'),
',', ' ')" />

XSL iterate over attribute and ignore some elements

I need to do rather simple thing of iterating over elements in my XML(more explanation under the XML)
<form>
<field index="1" name="field_X_1" group="firstGroup" type="String">
<value>Value of Field X 1 of first group</value>
</field>
<field index="1" name="field_Y_1" group="firstGroup" type="String">
<value>Value of Field Y 1 of first group</value>
</field>
<field index="2" name="field_X_2" group="firstGroup" type="String">
<value>Value of Field X 2 of first group</value>
</field>
<field index="2" name="field_Y_2" group="firstGroup" type="String">
<value>Value of Field Y 2 of first group</value>
</field>
<field index="1" name="field_A_1" group="secondGroup" type="String">
<value>Value of Field A 1 of second group</value>
</field>
<field index="1" name="field_B_1" group="secondGroup" type="String">
<value>Value of Field B 1 of second group</value>
</field>
<field index="2" name="field_A_2" group="secondGroup" type="String">
<value>Value of Field A 2 of second group</value>
</field>
<field index="2" name="field_B_2" group="secondGroup" type="String">
<value>Value of Field B 2 of second group</value>
</field>
</form>
Right now I am iterating over ALL fields of firstGroup and everytime I found that index has changed(by comparing index to index of sibbling) I add new line character).
Problem is I need only to iterate over index (but still keep distiction between firstGroup and secondGroup).
My output should look like
Value of Field X 1 of first group, Value of Field Y 1 of first group
Value of Field X 2 of first group, Value of Field Y 2 of first group
Value of Field A 1 of second group, Value of Field B 1 of second group
Value of Field A 2 of second group, Value of Field B 2 of second group
etc
My XSL now looks like
<xsl:for-each select='/form/field[#group="firstGroup"]'>
<xsl:sort select="#index" order="ascending"></xsl:sort>
<xsl:if test='preceding-sibling::*[#group="firstGroup"][1]/#index != #index and count(preceding-sibling::*) != 0 '>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:value-of select="//field[#name=concat('field_X_', #index,')]/value"/>
<xsl:value-of select="//field[#name=concat('field_Y_', #index,')]/value"/>
</xsl:for-each>
<!-- Differente iteration for second group-->
<xsl:text>
</xsl:text>
<xsl:for-each select='/form/field[#group="firstGroup"]'>
<xsl:sort select="#index" order="ascending"></xsl:sort>
<xsl:if test='preceding-sibling::*[#group="firstGroup"][1]/#index != #index and count(preceding-sibling::*) != 0 '>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:value-of select="//field[#name=concat('field_A_', #index,')]/value"/>
<xsl:value-of select="//field[#name=concat('field_B_', #index,')]/value"/>
</xsl:for-each>
<xsl:output method="text" />
<xsl:template match="form">
<!--* find all the groups *-->
<xsl:variable name="groups">
<xsl:call-template name="get-group-names">
<xsl:with-param name="nodes" select="field" />
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="process-all-groups">
<xsl:with-param name="group-names" select="$groups" />
</xsl:call-template>
</xsl:template>
<xsl:template name="get-group-names">
<xsl:param name="nodes" />
<xsl:param name="result-so-far" />
<xsl:choose>
<xsl:when test="not($nodes)">
<xsl:value-of select="$result-so-far" />
</xsl:when>
<xsl:when test="contains(
concat(' ', $result-so-far),
concat(' ', $nodes[1]/#group, ' '))" >
<xsl:call-template name="get-group-names">
<xsl:with-param name="nodes" select="$nodes[position() > 1]" />
<xsl:with-param name="result-so-far" select="$result-so-far" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="get-group-names">
<xsl:with-param name="nodes" select="$nodes[position() > 1]" />
<xsl:with-param name="result-so-far"
select="concat($result-so-far, $nodes[1]/#group, ' ')" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="process-all-groups">
<xsl:param name="group-names" />
<xsl:variable name="group" select="substring-before($group-names, ' ')"/>
<xsl:if test="not(string-length($group) = 0)">
<xsl:call-template name="index">
<xsl:with-param name="n" select="1" />
<xsl:with-param name="group" select="$group" />
</xsl:call-template>
<xsl:call-template name="process-all-groups">
<xsl:with-param name="group-names"
select="substring-after($group-names, ' ')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="index">
<xsl:param name="n" select="1" />
<xsl:param name="group" />
<xsl:variable name="with-n"
select="/form/field[#group = $group][#index = $n]" />
<xsl:if test="$with-n">
<xsl:for-each select="$with-n">
<xsl:sort use="#index" order="ascending" />
<xsl:value-of select="value" />
<xsl:if test="not(position() = last())">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:call-template name="index">
<xsl:with-param name="n" select="$n + 1" />
<xsl:with-param name="group" select="$group" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="field"></xsl:template>