 |
| XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

May 22nd, 2013, 08:16 AM
|
|
Authorized User
|
|
Join Date: May 2009
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
XSLT 1 transformation help
Hi all,
I am kind of stuck in implementing a rather tricky output for my given xml source.
My input is:
Code:
<PickUpOpeningHours>08:00 - 22:00</PickUpOpeningHours>
And I want an output similar to:
Code:
<SubSection SubTitle="OfficeHours">
<Paragraph Name="Monday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Tuesday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Wednesday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Thursday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Friday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Saturday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
<Paragraph Name="Sunday">
<Text>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCCCCCCCC</Text>
</Paragraph>
</SubSection>
Let me explain the output logic.
C: closes
O: opened
Time is represented in 24 hours.
1 hour = 4 x 15 min (4 quarters)
24 hours = 96 x 15 min (96 quarters)
Total characters (C or O) will be 96 in total, where each character represents single quarter of time.
The input xml could be of two different formats:
Code:
<PickUpOpeningHours>07:00 - 23:00</PickUpOpeningHours>
OR
Code:
<PickUpOpeningHours>08:30 - 12:00, 14:30 - 18:00</PickUpOpeningHours>
Can someone please help me out in devising some solution for the above problem using xslt 1?
Thanks.
|
|

May 22nd, 2013, 09:09 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
Does it really have to be 1.0?
First pick out the opening and closing times using substring-before and substring-after. Translate 08:00 to an opening number $O=32 (= 8*4 + 0*1), and 22:00 to $C=88 similarly. Then define a couple of strings which are sufficiently long sequences of letter O and letter C respectively, select subsequences of these using substring(X, 1, $O), substring(X, $O, ($C - $O)), and substring(X, $C), and concatenate the results.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
|
|

May 22nd, 2013, 09:29 AM
|
|
Authorized User
|
|
Join Date: May 2009
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks for replying. I have implemented it in xslt 2, but it is getting complicated and difficult to maintain :(
Here it is so far how it looks like:
Code:
<xsl:transform xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" exclude-result-prefixes=" xs xsl">
<xsl:import href="mapp2flags.xsl"/>
<xsl:output method="xml" version="1.0"/>
<xsl:param name="day"/>
<xsl:param name="closed24" select="'00:00 - 00:00'"/>
<xsl:param name="open24" select="'00:00 - 24:00'"/>
<xsl:variable name="weekDays">Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,</xsl:variable>
<xsl:variable name="delimiters" select="'|'"/>
<!-- xsl:template match="/">
<xsl:apply-templates select="OPENING_HOURS"/>
</xsl:template> -->
<xsl:template match="PickUpOpeningHours|DropOffOpeningHours">
<xsl:variable name="text">
<OPENHOURS>
<xsl:value-of select="concat('DAYMO - DAYSU: ',replace(replace(text(),'geschlossen',$closed24),'OPEN',$open24))"/>
</OPENHOURS>
</xsl:variable>
<xsl:apply-templates select="$text/OPENHOURS"/>
</xsl:template>
<xsl:template match="OPENHOURS">
<xsl:param name="pText"/>
<SubSection xmlns="http://www.opentravel.org/OTA/2003/05">
<xsl:attribute name="SubTitle"><xsl:value-of select="'OfficeHours'"/></xsl:attribute>
<xsl:choose>
<xsl:when test="contains(text(),',')">
<xsl:for-each select="tokenize(.,', ')">
<xsl:call-template name="run"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="run"/>
</xsl:otherwise>
</xsl:choose>
</SubSection>
</xsl:template>
<xsl:template name="run">
<xsl:param name="pText"/>
<xsl:variable name="frDay">
<xsl:choose>
<xsl:when test="contains(substring-before(.,':'),'-')">
<xsl:value-of select="substring-before(substring-after(substring-before(.,':'),'DAY'),' -')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after(substring-before(.,':'),'DAY')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="fromDay">
<xsl:call-template name="mapDay">
<xsl:with-param name="pDay" select="$frDay"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="tDay">
<xsl:choose>
<xsl:when test="contains(substring-before(.,':'),'-')">
<xsl:value-of select="substring-after(substring-before(.,':'),'- DAY')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after(substring-before(.,':'),'DAY')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="toDay">
<xsl:call-template name="mapDay">
<xsl:with-param name="pDay" select="$tDay"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="listToTokenize" select="concat(substring-before(concat($fromDay,substring-after($weekDays, $fromDay)), $toDay),$toDay,',')"/>
<xsl:call-template name="tokenize">
<xsl:with-param name="pText" select="$listToTokenize"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="pText"/>
<xsl:if test="string-length($pText)">
<Paragraph xmlns="http://www.opentravel.org/OTA/2003/05">
<xsl:attribute name="Name"><xsl:value-of select="substring-before($pText, ',')"/></xsl:attribute>
<Text xmlns="http://www.opentravel.org/OTA/2003/05">
<xsl:call-template name="mapHours">
<xsl:with-param name="pHours" select="substring-after(string(.),': ')"/>
</xsl:call-template>
</Text>
</Paragraph>
<xsl:call-template name="tokenize">
<xsl:with-param name="pText" select="substring-after($pText, ',')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="mapDay">
<xsl:param name="pDay"/>
<xsl:choose>
<xsl:when test="$pDay= 'MO'">Monday</xsl:when>
<xsl:when test="$pDay = 'TU'">Tuesday</xsl:when>
<xsl:when test="$pDay = 'WE'">Wednesday</xsl:when>
<xsl:when test="$pDay = 'TH'">Thursday</xsl:when>
<xsl:when test="$pDay = 'FR'">Friday</xsl:when>
<xsl:when test="$pDay = 'SA'">Saturday</xsl:when>
<xsl:when test="$pDay = 'SU'">Sunday</xsl:when>
</xsl:choose>
</xsl:template>
<!---->
<!--xsl:template name="setBlock">
<xsl:variable name="open" select="substring-after(text(),': ')"/>
<xsl:variable name="openToM" select="substring-after($open,':')"/>
<xsl:variable name="openTM" select="substring-before(substring-after($open,':'),' -')"/>
<xsl:variable name="openToHrs" select="concat(substring-after($open,' - '),':00')"/>
<xsl:variable name="closeToM" select="substring-after($open,' - ')"/>
<xsl:variable name="openFromHrs" select="concat(substring-before($open,' - '),':00')"/>
<xsl:variable name="openH" select="xs:time($openToHrs) - xs:time($openFromHrs)"/>
<xsl:variable name="openHrs" select="substring-before(string(substring-after(string($openH),'PT')),'H')"/>
<xsl:variable name="randDate" select="'1999-01-01T'"></xsl:variable>
<xsl:variable name="openH" select="xs:dateTime(concat($randDate,$openToHrs)) - xs:dateTime(concat($randDate,$openFromHrs))"/>
<xsl:variable name="randDate1" select="xs:dateTime('2013-06-22T01:00:00')"></xsl:variable>
<xsl:variable name="randDate2" select="xs:dateTime('2013-06-22T23:00:00')"></xsl:variable>
<xsl:variable name="durationDate" select="$randDate2 - $randDate1"></xsl:variable>
<xsl:variable name="openMts">
<xsl:choose>
<xsl:when test="contains(string($openH),'H')">
<xsl:value-of select="substring-before(string(substring-after(string(xs:time($openToHrs) - xs:time($openFromHrs)),'H')),'M')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before(string(substring-after(string(xs:time($openToHrs) - xs:time($openFromHrs)),'PT')),'M')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="MtsMultiplikator">
<xsl:choose>
<xsl:when test="$openMts =''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="round(xs:double($openMts) div 15)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="HrsMultiplikator">
<xsl:choose>
<xsl:when test="$openHrs =''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="round(xs:double($openHrs) * 4)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="closeToHrsMultipl">
<xsl:choose>
<xsl:when test="$open =''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="number(substring-before($open,':'))*4"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="closeToMtsMultipl">
<xsl:choose>
<xsl:when test="$openTM =''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="round(xs:double($openTM) div 15)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="OpenQuarters" select="$MtsMultiplikator + $HrsMultiplikator"/>
<xsl:variable name="CloseQuarters" select="$closeToHrsMultipl + $closeToMtsMultipl"/>
<xsl:variable name="CloseEnd" select="number('96') - ($OpenQuarters + $CloseQuarters)"/>
<Text>
<xsl:call-template name="Schleife">
<xsl:with-param name="Zaehler" select="number('1')"/>
<xsl:with-param name="ZaehlerAnz" select="number($CloseQuarters)"/>
<xsl:with-param name="cHar" select="'C'"/>
</xsl:call-template>
<xsl:call-template name="Schleife">
<xsl:with-param name="Zaehler" select="number('1')"/>
<xsl:with-param name="ZaehlerAnz" select="number($OpenQuarters)"/>
<xsl:with-param name="cHar" select="'O'"/>
</xsl:call-template>
<xsl:call-template name="Schleife">
<xsl:with-param name="Zaehler" select="number('1')"/>
<xsl:with-param name="ZaehlerAnz" select="number($CloseEnd)"/>
<xsl:with-param name="cHar" select="'C'"/>
</xsl:call-template>
</Text>
</xsl:template>->
<xsl:template name="Schleife">
<xsl:param name="Zaehler"/>
<xsl:param name="ZaehlerAnz"/>
<xsl:param name="cHar"/>
<xsl:choose>
<xsl:when test="$Zaehler <= number($ZaehlerAnz)">
<xsl:value-of select="$cHar"/>
<xsl:call-template name="Schleife">
<xsl:with-param name="Zaehler" select="$Zaehler + 1"/>
<xsl:with-param name="ZaehlerAnz" select="$ZaehlerAnz"/>
<xsl:with-param name="cHar" select="$cHar"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="Abbruch"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>-->
<xsl:template name="Abbruch">
<xsl:comment>Schleife beendet!</xsl:comment>
</xsl:template>
</xsl:transform>
Code:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:f="http://www.traveltainment.de/xslt/functions" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Transforms a concatenated sequence of time intervals ('08:13-13:00, 15:00-18:00')
into a flag string ('CCCCCCCOOOOOO...') where each flag represents a 15 minutes interval
-->
<xsl:function name="f:getOpenFlags" as="xs:string">
<xsl:param name="openingData" as="xs:string"/>
<xsl:variable name="intervals" select="tokenize($openingData, ',\s*')"/>
<xsl:variable name="openFirst" select="substring-before($intervals[1], ' - ')" as="xs:string"/>
<xsl:variable name="openLast" select="substring-after($intervals[last()], ' - ')" as="xs:string"/>
<xsl:variable name="initialClosed" select="f:interval2flags('C', '00:00', $openFirst)"/>
<xsl:variable name="intermediate" select="f:getOpenFlagsRC($intervals)"/>
<xsl:variable name="finalClosed" select="f:interval2flags('C', $openLast, '24:00')"/>
<xsl:sequence select="string-join(($initialClosed, $intermediate, $finalClosed), '')"/>
</xsl:function>
<!-- Transforms a start time and an end time in a flag string ('CCCC')
where each flag represents a 15 minutes interval.
-->
<xsl:function name="f:interval2flags" as="xs:string">
<xsl:param name="flag" as="xs:string"/>
<xsl:param name="start" as="xs:string"/>
<xsl:param name="end" as="xs:string"/>
<xsl:variable name="numUnits" as="xs:double">
<xsl:choose>
<xsl:when test="$start eq '00:00' and $end eq '24:00'">
<xsl:sequence select="24 * 4"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="startTime" select="xs:time(concat($start, ':00'))" as="xs:time"/>
<xsl:variable name="endTime" select="xs:time(concat($end, ':00'))" as="xs:time"/>
<xsl:variable name="diff" select="$endTime - $startTime" as="xs:dayTimeDuration"/>
<xsl:variable name="duration" select="if ($endTime ne $startTime and $endTime eq xs:time('00:00:00')) then ($diff + xs:dayTimeDuration('PT24H')) else $diff"/>
<xsl:sequence select="$duration div xs:dayTimeDuration('PT15M')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="string-join(for $i in 1 to xs:integer($numUnits) return $flag, '')"/>
</xsl:function>
<!-- Recursive helper function ofr 'getOpenFlags'.
-->
<xsl:function name="f:getOpenFlagsRC" as="xs:string*">
<xsl:param name="intervals" as="xs:string*"/>
<xsl:variable name="i1" select="$intervals[1]"/>
<xsl:variable name="start" select="substring-before($i1, ' - ')"/>
<xsl:variable name="end" select="substring-after($i1, ' - ' )"/>
<xsl:variable name="remaining" select="$intervals[position() gt 1]"/>
<!-- the flags for this "open" interval -->
<xsl:sequence select="f:interval2flags('O', $start, $end)"/>
<xsl:if test="exists($remaining)">
<!-- the flags for the "closed" between this interval and the next one -->
<xsl:sequence select="f:interval2flags('C', $end, substring-before($remaining[1], ' - '))"/>
<!-- the flags for the remaining intervals -->
<xsl:sequence select="f:getOpenFlagsRC($remaining)"/>
</xsl:if>
</xsl:function>
<!--xsl:template match="/">
<xsl:variable name="testData" select="'00:00 - 24:00'" as="xs:string"/>
<xsl:sequence select="f:getOpenFlags($testData)"/>
</xsl:template-->
<xsl:template name="mapHours">
<xsl:param name="pHours"/>
<xsl:sequence select="f:getOpenFlags($pHours)"/>
</xsl:template>
</xsl:transform>
It is somehow working when input is:
Code:
<PickUpOpeningHours>07:00 - 24:00</PickUpOpeningHours>
But fails when the input is:
Code:
<PickUpOpeningHours>08:30 - 12:00, 14:30 - 18:00</PickUpOpeningHours>
I am finding it difficult to debug. Could you please give it a look and identify the problem?
Thanks.
|
|

May 22nd, 2013, 10:15 AM
|
|
Authorized User
|
|
Join Date: May 2009
Posts: 32
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
any pointer for my last example script?
|
|

May 22nd, 2013, 10:39 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
I can't debug it for you, but I can make a couple of suggestions from glancing at your code.
Firstly, constructs like this:
Code:
<xsl:variable name="MtsMultiplikator">
<xsl:choose>
<xsl:when test="$openMts =''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="round(xs:double($openMts) div 15)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
in XSLT 2.0 can be better written as
Code:
<xsl:variable name="MtsMultiplikator" select="if ($openMts =''') then 0 else round(xs:double($openMts) div 15)"/>
This has several benefits: it makes your code a lot shorter, making it easier to see the bugs, and it's also more efficient because the variable is now a number, not a result tree fragment.
Secondly, the conversion from a time such as 08:00 to a number of 15-minute periods since midnight can probably be best expressed as
Code:
((xs:time(concat($t, ':00)) - xs:time('00:00:00')) div xs:dayTimeDuration('PT15M')
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
|
|
 |