Trying to calculate day of the week number from date. Found some examples in the internet, but instead of day of the week number i see this : NaN.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="date">
<xsl:copy>
<xsl:call-template name="date-format">
<xsl:with-param name="date-time" select="."/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="date-format">
<xsl:param name="date-time"/>
<xsl:param name="date" select="substring-before($date-time,'T')"/>
<xsl:param name="year" select="substring-before($date,'-')"/>
<xsl:param name="month"
select="substring-before(substring-after($date,'-'),'-')"/>
<xsl:param name="day" select="substring-after(substring-after($date,'-'),'-')"/>
<xsl:variable name="a" select="floor((14 - $month) div 12)"/>
<xsl:variable name="y" select="$year - $a"/>
<xsl:variable name="m" select="$month + 12 * $a - 2"/>
<xsl:value-of select="($day + $y + floor($y div 4) - floor($y div 100)
+ floor($y div 400) + floor((31 * $m) div 12)) mod 7"/>
</xsl:template>
</xsl:stylesheet>
.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="test2.xsl" type="text/xsl" ?>
<document>
<date>2013-01-01</date>
<date>2013-05-24</date>
<date>2013-12-25</date>
<date>1957-07-13</date>
<date>1776-07-04</date>
</document>
The following stylesheet:
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:strip-space elements="*"/>
<xsl:template match="date">
<xsl:call-template name="day-of-week">
<xsl:with-param name="date" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="day-of-week">
<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:variable name="JDN" select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
<xsl:value-of select="($JDN + 1) mod 7" />
</xsl:template>
</xsl:stylesheet>
when applied to your input example:
<document>
<date>2013-01-01</date>
<date>2013-05-24</date>
<date>2013-12-25</date>
<date>1957-07-13</date>
<date>1776-07-04</date>
</document>
will return the following result:
<?xml version="1.0" encoding="UTF-8"?>
25364
Note:
The main problem with your attempt is this:
<xsl:param name="date" select="substring-before($date-time,'T')"/>
Your input has dates, not date-times, and they do not contain "T".
Related
i am new to XSLT
How to compare the date strings in XSLT and output the result
below is my input xml
<?xml version="1.0" encoding="UTF-8"?>
<dates>
<date1>2003-09-15T16:53:22.000-07:00</date1>
<date2>2003-09-15T16:53:23.000-07:00</date2>
</dates>
below is my XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="date1" select="/dates/date1"/>
<xsl:variable name="date2" select="/dates/date2"/>
<xsl:template match="/">
<xsl:if test="$date1 > $date2">
date1 is greater
</xsl:if>
<xsl:if test="$date1 = $date2">
both dates are equal
</xsl:if>
<xsl:if test="$date1 <= $date2">
date1 is lesser than date2
</xsl:if>
</xsl:template>
</xsl:stylesheet>
now in XSLT i want to compare the above dates, so is it possible in XSLT 1.0 to compare (greater,lesser, equals) the dates
i believe in xslt 1.0 its not possible, if possible please share the information.
if it can be done in XSLT 2.0 please help me how i can fix this,
in my current ongoing study project, i have used XSLT 1.0, so please suggest answer in XSLT 1.0 thanks
To do this in XSLT 1.0, you must first convert the given dateTimes to numerical values and equalize them to a common time zone.
In the following stylesheet, each dateTime is converted to the number of seconds elapsed since noon UTC of November 24, 4714 BC - see: https://en.wikipedia.org/wiki/Julian_day
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:strip-space elements="*"/>
<xsl:template match="dates">
<xsl:variable name="date1">
<xsl:call-template name="dateTime-to-seconds">
<xsl:with-param name="dateTime" select="date1" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="date2">
<xsl:call-template name="dateTime-to-seconds">
<xsl:with-param name="dateTime" select="date2" />
</xsl:call-template>
</xsl:variable>
<result>
<xsl:choose>
<xsl:when test="$date1 < $date2">date1 occurs earlier than date2</xsl:when>
<xsl:when test="$date1 = $date2">the two dates are concurrent</xsl:when>
<xsl:when test="$date1 > $date2">date1 occurs later than date2</xsl:when>
</xsl:choose>
</result>
</xsl:template>
<xsl:template name="dateTime-to-seconds">
<xsl:param name="dateTime"/>
<xsl:variable name="date" select="substring-before($dateTime, 'T')" />
<xsl:variable name="time" select="substring-after($dateTime, 'T')" />
<xsl:variable name="local-time" select="substring($time, 1, string-length($time) - 6)" />
<xsl:variable name="offset" select="substring-after($time, $local-time)" />
<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="hour" select="substring($local-time, 1, 2)" />
<xsl:variable name="minute" select="substring($local-time, 4, 2)" />
<xsl:variable name="second" select="substring($local-time, 7)" />
<xsl:variable name="offset-sign" select="1 - 2 * starts-with($offset, '-')" />
<xsl:variable name="offset-hour" select="substring($offset, 2, 2) * $offset-sign" />
<xsl:variable name="offset-minute" select="substring($offset, 5, 2) * $offset-sign" />
<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:variable name="jd" select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
<xsl:value-of select="86400*$jd + 3600*$hour + 60*$minute + $second - 3600*$offset-hour - 60*$offset-minute" />
</xsl:template>
</xsl:stylesheet>
Applied to the following test input:
XML
<dates>
<date1>2003-09-15T16:53:22.000-07:00</date1>
<date2>2003-09-15T17:53:22.000-06:00</date2>
</dates>
the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<result>the two dates are concurrent</result>
Looking to parse out a namespace from a full class name in xml.
Data example:
<results>
<test-case name="Co.Module.Class.X">
</results>
End result (going to csv format):
,Co.Module.Class
Stylesheet:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="text" indent="yes" encoding="ISO-8859-1"/>
<xsl:param name="delim" select="','" />
<xsl:param name="quote" select="'"'" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
FullTestName, Namespace
<xsl:apply-templates select="//test-case" />
</xsl:template>
<xsl:template match="test-case">
<xsl:apply-templates />
<xsl:value-of select="#name" />
<xsl:value-of select="$delim" />
<xsl:value-of select="function to go here for nameWithJustNamespace" />
<xsl:value-of select="$break" />
</xsl:template>
I understand the process would need a last index of "." to be called once, yet I'm not finding XSLT to have that function. How to best accomplish this?
To do this in pure XSLT 1.0, you need to call a named recursive template, e.g.:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/results">
<xsl:call-template name="remove-last-token">
<xsl:with-param name="text" select="test-case/#name"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="remove-last-token">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="'.'"/>
<xsl:value-of select="substring-before($text, $delimiter)"/>
<xsl:if test="contains(substring-after($text, $delimiter), $delimiter)">
<xsl:value-of select="$delimiter"/>
<xsl:call-template name="remove-last-token">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
This pure XSLT 1.0 transformation (shorter, no conditional XSLT operations, single template):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="test-case[contains(#name, '.')]">
<xsl:param name="pDotIndex" select="0"/>
<xsl:variable name="vNextToken"
select="substring-before(substring(#name, $pDotIndex+1), '.')"/>
<xsl:value-of select="concat(substring('.', 2 - ($pDotIndex > 0)),$vNextToken)"/>
<xsl:variable name="vNewDotIndex" select="$pDotIndex+string-length($vNextToken)+1"/>
<xsl:apply-templates
select="self::node()[contains(substring(#name,$vNewDotIndex+1), '.')]">
<xsl:with-param name="pDotIndex" select="$vNewDotIndex"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<results>
<test-case name="Co.Module.Class.X"/>
</results>
produces the wanted, correct result:
Co.Module.Class
Part 2
With a slight modification the following transformation produces the complete CSV:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="test-case[contains(#name, '.')]">
<xsl:param name="pDotIndex" select="0"/>
<xsl:variable name="vNextToken"
select="substring-before(substring(#name, $pDotIndex+1), '.')"/>
<xsl:value-of select="concat(substring(',', 2 - (position() > 1)),
substring('.', 2 - ($pDotIndex > 0)), $vNextToken)"/>
<xsl:variable name="vNewDotIndex" select="$pDotIndex+string-length($vNextToken)+1"/>
<xsl:apply-templates
select="self::node()[contains(substring(#name,$vNewDotIndex+1), '.')]">
<xsl:with-param name="pDotIndex" select="$vNewDotIndex"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
When applied on this XML document:
<results>
<test-case name="Co.Module.Class.X"/>
<test-case name="Co2.Module2.Class2.Y"/>
<test-case name="Co3.Module3.Class3.Z"/>
</results>
the wanted, correct (CSV) result is produced:
Co.Module.Class,Co2.Module2.Class2,Co3.Module3.Class3
i've the below xml.
<?xml version="1.0" encoding="UTF-8"?>
<chapter num="A">
<title>
<content-style font-style="bold">PART 1 GENERAL PRINCIPLES</content-style>
</title>
<section level="sect1">
<section level="sect2" number-type="manual" num="1.">
<title>INTRODUCTION OF INDIA TO NEW ERA AND THE EXISTING</title>
</section>
</section>
</chapter>
by using the below xslt i'm able to captalize each word.
<xsl:element name="{concat(translate(substring(name(), 1, 1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), substring(name(), 2))}">
and i get the below output.
Introduction Of India To New Era And The Existing
but i want as below.
Introduction of India to New Era and the Existing
i.e. i want to ignore the conjunctions. please let me know how do i do it.
Thanks
This transformation uses the strSplit-to-Words template of the FXSL library (written in pure XSLT 1.0) and doesn't require any extension functions with the exception of the de-facto standard xxx:node-set():
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:import href="strSplit-to-Words.xsl"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:variable name="vLowercase" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="vConjunctions" select=
"'|AND|THE|OF|A|AN|TO|FOR|AT|ON|IN|INTO|AMONG|FROM|'"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="pDelims" select="'
'"/>
<xsl:template match="/">
<xsl:variable name="vwordNodes">
<xsl:call-template name="str-split-to-words">
<xsl:with-param name="pStr" select="/"/>
<xsl:with-param name="pDelimiters"
select="$pDelims"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vwordNodes)/*[normalize-space()]"/>
</xsl:template>
<xsl:template match="word">
<xsl:if test="not(position() = 1)"><xsl:text> </xsl:text></xsl:if>
<xsl:choose>
<xsl:when test="contains($vConjunctions, concat('|',.,'|'))">
<xsl:value-of select="translate(substring(., 1, 1), $vUppercase, $vLowercase)"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="substring(., 1, 1)"/></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="translate(substring(., 2), $vUppercase, $vLowercase)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<title>INTRODUCTION OF INDIA TO NEW ERA AND THE EXISTING</title>
the wanted, correct result is produced:
Introduction of India to New Era and the Existing
Piggybacking on the answer provided by #NavinRawat, here's an XSLT 1.0 variant. Note that it requires the use of the EXSLT Extension Library's node-set() function.
When this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pConjunctions" select="'|OF|TO|AND|THE|'"/>
<xsl:variable name="vUppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="vLowercase" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:template match="/*/*/*/title">
<xsl:variable name="vTitleWords">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="delimiter" select="' '"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($vTitleWords)/*"/>
</xsl:template>
<xsl:template match="token">
<xsl:if test="position() > 1"> </xsl:if>
<xsl:choose>
<xsl:when test="contains($pConjunctions, concat('|', ., '|'))">
<xsl:value-of select="translate(., $vUppercase, $vLowercase)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of
select="concat(
substring(., 1, 1),
translate(substring(., 2), $vUppercase, $vLowercase)
)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:choose>
<xsl:when test="contains($text,$delimiter)">
<xsl:element name="token">
<xsl:value-of select="substring-before($text,$delimiter)"/>
</xsl:element>
<xsl:call-template name="tokenize">
<xsl:with-param
name="text"
select="substring-after($text,$delimiter)"/>
<xsl:with-param
name="delimiter"
select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$text">
<xsl:element name="token">
<xsl:value-of select="$text"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
...is run against the provided XML:
<?xml version="1.0" encoding="UTF-8"?>
<chapter num="A">
<title>
<content-style font-style="bold">PART 1 GENERAL PRINCIPLES</content-style>
</title>
<section level="sect1">
<section level="sect2" number-type="manual" num="1.">
<title>INTRODUCTION OF INDIA TO NEW ERA AND THE EXISTING</title>
</section>
</section>
</chapter>
...the wanted result is produced:
Introduction of India to New Era and the Existing
Obviously, the XSLT 2.0 variant is much cleaner and doesn't require a two-pass transformation, but if you're stuck with XSLT 1.0 and can utilize EXSLT, this will get you where you want to go.
Try this one:
<?xml version='1.0'?>
<xslt:stylesheet version="2.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="Conjunction">(of)|(to)|(and)|(the)</xsl:param>
<xsl:template match="chapter/section/section/title">
<xsl:call-template name="changeUpperCase">
<xsl:with-param name="Text" select="text()"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="changeUpperCase">
<xsl:param name="Text"/>
<xsl:value-of select="for $EachToken in tokenize(lower-case($Text), ' ')
return
if(matches($EachToken, $Conjunction))
then
$EachToken
else
concat(upper-case(substring($EachToken, 1, 1)), substring($EachToken, 2))"/>
</xsl:template>
</xslt:stylesheet>
xslt have function(like substring vice versa) or how to solve it? I had xml:
<document>
<Line>
<Line-Item>
<LineNumber>10</LineNumber>
<EAN>111</EAN>
<BIC>123123</BIC>
<SIC>AVD091</SIC>
</Line-Item>
</Line>
<Line>
<Line-Item>
<LineNumber>20</LineNumber>
<EAN>22222</EAN>
<BIC>3232332</BIC>
<SIC>AVD25482</SIC>
</Line-Item>
</Line>
</document>
needed output:
10 111 123123 AVD091
20 22222 3232332 AVD25482
Field line number start from 1 column position, EAN start from 11 column position, BIC start from 19 and SIC from 31.
Try this XSLT 1.0 style-sheet. The pad template is an XSLT 1.0 version of Martin's mf:pad function.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="document/Line/Line-Item"/>
</xsl:template>
<xsl:template name="pad">
<xsl:param name="value" />
<xsl:param name="width" />
<xsl:variable name="col-max" select="' '"/>
<xsl:value-of select="substring( concat($value,$col-max), 1, $width)" />
</xsl:template>
<xsl:template match="Line-Item" >
<xsl:call-template name="pad" >
<xsl:with-param name="value" select="LineNumber"/>
<xsl:with-param name="width" select="10" />
</xsl:call-template>
<xsl:call-template name="pad" >
<xsl:with-param name="value" select="EAN"/>
<xsl:with-param name="width" select="8" />
</xsl:call-template>
<xsl:call-template name="pad" >
<xsl:with-param name="value" select="BIC"/>
<xsl:with-param name="width" select="12" />
</xsl:call-template>
<xsl:value-of select="SIC" />
<xsl:value-of select="'
'" />
</xsl:template>
<xsl:template match="*" />
</xsl:stylesheet>
This short and generic transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<my:fields>
<fieldset name="LineNumber" width="10"/>
<fieldset name="EAN" width="8"/>
<fieldset name="BIC" width="12"/>
</my:fields>
<xsl:variable name="vSpaces" select="' '"/>
<xsl:variable name="vFields" select="document('')/*/my:fields/*"/>
<xsl:template match="Line-Item">
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="Line-Item/*">
<xsl:value-of select=
"concat(.,
substring($vSpaces,
1,
$vFields[#name = name(current())]/#width
-
string-length()
)
)"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<document>
<Line>
<Line-Item>
<LineNumber>10</LineNumber>
<EAN>111</EAN>
<BIC>123123</BIC>
<SIC>AVD091</SIC>
</Line-Item>
</Line>
<Line>
<Line-Item>
<LineNumber>20</LineNumber>
<EAN>22222</EAN>
<BIC>3232332</BIC>
<SIC>AVD25482</SIC>
</Line-Item>
</Line>
</document>
produces the wanted, correct result:
10 111 123123 AVD091
20 22222 3232332 AVD25482
Do note:
The element my:fields can be put in its own XML document. Thus, no modifications would be required to the XSLT code if some fields widths need to be modified.
Here is a sample stylesheet (XSLT 2.0, sorry, started writing before your comment indicated a request for 1.0):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="col-max" as="xs:string" select="' '"/>
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:function name="mf:pad" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="col-length" as="xs:integer"/>
<xsl:sequence select="concat($input, substring($col-max, 1, $col-length - string-length($input)))"/>
</xsl:function>
<xsl:template match="Line">
<xsl:if test="position() > 1">
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="LineNumber">
<xsl:sequence select="mf:pad(., 10)"/>
</xsl:template>
<xsl:template match="EAN">
<xsl:sequence select="mf:pad(., 9)"/>
</xsl:template>
<xsl:template match="BIC">
<xsl:sequence select="mf:pad(., 12)"/>
</xsl:template>
<xsl:template match="SIC">
<xsl:sequence select="mf:pad(., string-length())"/>
</xsl:template>
</xsl:stylesheet>
Converting the hour seems to take a lot of work... there must be a simpler way.
<xsl:variable name="hour12">
<xsl:choose>
<xsl:when test="$hour24 < 0">
<xsl:value-of select="12 + $hour24" />
</xsl:when>
<xsl:when test="$hour24 = 0">
<xsl:value-of select="12" />
</xsl:when>
<xsl:when test="$hour24 = 12">
<xsl:value-of select="$hour24" />
</xsl:when>
<xsl:when test="$hour24 > 12">
<xsl:value-of select="$hour24 - 12" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$hour24" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Any suggestions?
Oh...I love how boolean values equal 0 or 1. It makes life so much easier...
<xsl:variable name="hour12">
<xsl:value-of select="$hour24 - (12 * ($hour24 > 12)) + (12 * ($hour24 = 0))" />`
</xsl:variable>
And for the a/p identifier
<xsl:variable name="ap">
<xsl:value-of select="substring('ap', 1 + ($hour24 >= 12), 1)" />
</xsl:variable>
For the time conversion, here is something which I find simpler:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="time/text()">
<xsl:variable name="vZ" select="(.+12) mod 12"/>
<xsl:value-of select="$vZ - ($vZ -12)*($vZ=0)"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<t>
<time>-3</time>
<time>0</time>
<time>7</time>
<time>12</time>
<time>17</time>
<time>24</time>
</t>
the wanted, correct result is produced:
<t>
<time>9</time>
<time>12</time>
<time>7</time>
<time>12</time>
<time>5</time>
<time>12</time>
</t>
For am/pm (if my understanding for the edge cases is correct) we add this code:
<xsl:variable name="vNorm" select=
"not(. >= 0)*(24 +.)
+
(. >=0 and not(. = 24))*.
+
not(. = 24)
"/>
<xsl:value-of select="$vPeriods[1+($vNorm>=12)]"/>
The complete transformation becomes:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:timePeriods>
<p>am</p>
<p>pm</p>
</my:timePeriods>
<xsl:variable name="vPeriods" select=
"document('')/*/my:timePeriods/*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="time/text()">
<xsl:variable name="vZ" select="(.+12) mod 12"/>
<xsl:value-of select="$vZ - ($vZ -12)*($vZ=0)"/>
<xsl:variable name="vNorm" select=
"not(. >= 0)*(24 +.)
+
(. >=0 and not(. = 24))*.
+
not(. = 24)
"/>
<xsl:value-of select="$vPeriods[1+($vNorm>=12)]"/>
</xsl:template>
</xsl:stylesheet>
and when applied to the same XML document (above) the result is:
<t>
<time>9pm</time>
<time>12am</time>
<time>7am</time>
<time>12pm</time>
<time>5pm</time>
<time>12am</time>
</t>