How to convert a negative decimal into hexadecimal using xslt 1 - xslt

I would like to convert negative and positive decimal into hexadecimal using xslt 1.0.
There's already a topic related to this question here but the answer is given using xslt 2.0.
I tried to reproduce the template using xslt 1.0 but it always returns an empty value.
<xsl:template name="convertDecToHex">
<xsl:param name="pInt" />
<xsl:variable name="vMinusOneHex64"><xsl:number>18446744073709551615</xsl:number></xsl:variable>
<xsl:variable name="vCompl">
<xsl:choose>
<xsl:when test="$pInt > 0">
<xsl:value-of select="$pInt" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$vMinusOneHex64 + $pInt + 1" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="vCompl = 0">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="vCompl > 16">
<xsl:variable name="result">
<xsl:call-template name="convertDecToHex">
<xsl:with-param name="pInt" select="$vCompl div 16" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat($result,substring('0123456789ABCDEF',($vCompl div 16) + 1,1))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('',substring('0123456789ABCDEF',($vCompl div 16) + 1,1))" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Could you help me making it work?

To convert a decimal number to 32-bit signed hexadecimal in pure XSLT 1.0:
<xsl:template name="dec2signedhex">
<xsl:param name="decimal"/>
<xsl:variable name="n">
<xsl:choose>
<xsl:when test="$decimal < 0">
<xsl:value-of select="$decimal + 4294967296"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$decimal"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="q" select="floor($n div 16)"/>
<xsl:if test="$q">
<xsl:call-template name="dec2signedhex">
<xsl:with-param name="decimal" select="$q"/>
</xsl:call-template>
</xsl:if>
<xsl:value-of select="substring('0123456789ABCDEF', $n mod 16 + 1, 1)"/>
</xsl:template>

Related

Add 3 hours to Datetime in Xslt 1.0

I have a value <delivery-at>31-Oct-2020 01:03 PM</delivery-at>, instead of the exact time need a three hour time window. For eg need to display value as "31-Oct-2020 01:00 PM - 31-Oct-2020 04:00 PM" in xslt
I could do it using the following
<xsl:template name= "get-expected-eta">
<xsl:variable name= "etadatetime" select= "delivery-at" />
<xsl:if test = "$etadatetime != '' ">
<xsl:variable name= "etadate" select= "substring($etadatetime, 1, 12)" />
<xsl:variable name= "etatime" select= "substring($etadatetime, 13, 15)" />
<xsl:variable name= "etahour" select= "substring($etatime, 1, 2)" />
<xsl:variable name= "etatimecomponent" select= "substring($etatime, 7, 8)" />
<xsl:variable name= "begin-time">
<xsl:choose>
<xsl:when test= "$etatimecomponent='AM'">
<xsl:choose>
<xsl:when test= "$etahour = 12">
<xsl:value-of select= "00"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select= "$etahour"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test= "$etahour = 12">
<xsl:value-of select= "$etahour"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select= "$etahour + 12"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name= "end-time" >
<xsl:choose>
<xsl:when test= "$begin-time + 3 >= 24">
<xsl:value-of select= "($begin-time + 3) - 24"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select= "$begin-time + 3"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name= "from-time" select = "concat($etahour, ' ',$etatimecomponent)"/>
<xsl:variable name= "to-time">
<xsl:choose>
<xsl:when test= "number($end-time) >= 12">
<xsl:choose>
<xsl:when test= "$end-time = 12">
<xsl:value-of select= "12"/> PM
</xsl:when>
<xsl:otherwise>
<xsl:value-of select= "$end-time - 12"/> PM
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test= "$end-time = 0">
<xsl:value-of select= "12"/> AM
</xsl:when>
<xsl:otherwise>
<xsl:value-of select= "$end-time"/> AM
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Expected ETA -->
<xsl:value-of select = '$etadate'/>(<xsl:value-of select = '$from-time'/> - <xsl:value-of select = '$to-time'/>)
</xsl:if>
</xsl:template>

Numbered bookmarks in PDF output from DITA bookmaps with and without parts

I am trying to create PDF output with numbered headings using the DITA OT and a custom plugin. By default, the output contains part numbers, chapter numbers and appendix number in the headings and the TOC, but no numbers in the bookmarks. So far, I have managed to number all the remaining topics in the headings and the TOC, like so (the chapter numbers restart in every part):
bookmap
part I
chapter 1
topic 1.1
topic 1.2
chapter 2
part II
chapter 1
However, I cannot get the same numbers for the bookmarks.
I am using the following code (or override) to select the bookmarks that must be numbered:
<xsl:template match="*[contains(#class, ' topic/topic ')]" mode="bookmark">
<xsl:variable name="mapTopicref" select="key('map-id', #id)[1]"/>
<xsl:variable name="topicTitle">
<xsl:call-template name="getNavTitle"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$mapTopicref[#toc = 'yes' or not(#toc)] or
not($mapTopicref)">
<fo:bookmark>
<xsl:attribute name="internal-destination">
<xsl:call-template name="generate-toc-id"/>
</xsl:attribute>
<xsl:if test="$bookmarkStyle!='EXPANDED'">
<xsl:attribute name="starting-state">hide</xsl:attribute>
</xsl:if>
<fo:bookmark-title>
<xsl:choose>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/part ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/appendix ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/chapter ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
</xsl:choose>
<xsl:value-of select="normalize-space($topicTitle)"/>
</fo:bookmark-title>
<xsl:apply-templates mode="bookmark"/>
</fo:bookmark>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates mode="bookmark"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I am using the following code to create the numbers (derived from an example in DITA for Print):
<xsl:template name="getChapterPrefix">
<xsl:variable name="topicType">
<xsl:call-template name="determineTopicType"/>
</xsl:variable>
<xsl:variable name="partsCount">
<xsl:value-of select="count($map//*[contains(#class, ' bookmap/part')])"/>
</xsl:variable>
<xsl:variable name="containingChapter" select="ancestor-or-self::*[contains(#class, ' topic/topic')][position()=1]"/>
<xsl:variable name="id" select="$containingChapter/#id"/>
<xsl:variable name="topicChapters">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/chapter')]"/>
</xsl:variable>
<xsl:variable name="topicAppendices">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/appendix')]"/>
</xsl:variable>
<xsl:variable name="topicParts">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/part')]"/>
</xsl:variable>
<xsl:variable name="chapterNumber">
<xsl:choose>
<xsl:when test="$topicChapters/*[#id = $id]">
<xsl:choose>
<xsl:when test="$partsCount=0"> <!-- Bookmaps without parts work fine -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise> <!-- This does not work yet. -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$topicAppendices/*[#id = $id]">
<xsl:number format="A" value="count($topicAppendices/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:when test="$topicParts/*[#id = $id]">
<xsl:number format="I" value="count($topicParts/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$chapterNumber != ''">
<xsl:value-of select="$chapterNumber"/>
</xsl:when>
</xsl:choose>
</xsl:template>
With this code, parts, appendices and bookmaps without parts are numbered correctly. However, for bookmaps with parts, chapters are numbered consecutively, which is inconsistent.
bookmap
part I
chapter 1
topic 1.1
topic 1.2
chapter 2
part II
chapter 3
Can anybody help me to correct this?
I just found a way to obtain the result I want. The piece of code that calculates the chapter number for bookmaps with parts was modified als follows:
<!-- If there's something in $topicChapters with an id that matches the id of the
context node, then I'm inside a chapter. -->
<xsl:when test="$topicChapters/*[#id = $id]">
<xsl:choose>
<xsl:when test="$partsCount=0"> <!-- Bookmaps without parts -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise> <!-- Bookmaps with parts. -->
<xsl:number format="1" value="count(//*[contains(#class,' bookmap/chapter ')][#id =$id]/preceding-sibling::*)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
This is probably everything but elegant, but then, I'm a tech writer ...

reformatting dates with square brackets

When transferring my XML-files to TeX I try to reformat dates – my publisher said I had to use a smaller horizontal space between dates – and can't manage to go beyond the first step.
My input file is this
<a>
<date>January 1900</date>
<date>2. 2. 1902</date>
<date>3. [3]. 1903</date>
<date>[4. 4. 1904]</date>
</a>
where brackets mean that the date is not certain. There are all possible combination of brackets, e.g. second number of the year: 1[9]00. I created a command \mini which makes small space in TeX:
\newcommand{\mini}{\,}
The result after the xslt should be:
January 1900
2.{\mini}2.{\mini}1902
3.{\mini}[3].{\mini}1903
[4.{\mini}4.{\mini}1904]
I wrote a function, which tries to extract the square brackets and store their position to a variable and afterwards concat them back again. But as I don't manage to get the variables to show correct positions, I'm stuck:
<xsl:function name="foo:date-translate">
<xsl:param name="date-string" as="xs:string"/>
<xsl:variable name="opening-square-bracket" as="xs:integer" select="count(substring-before($date-string,'['))"/>
<xsl:variable name="closing-square-bracket" as="xs:integer" select="count(substring-before($date-string,'['))"/>
<xsl:variable name="date-string-without-square-brackets" as="xs:string" select="replace(replace($date-string,'\[',''),'\]','')"/>
<xsl:choose>
<xsl:when test="matches($date-string-without-square-brackets,'\d{1,2}. \d{1,2}. \d{4}')">
<xsl:choose>
<xsl:when test="not(contains($date-string,'['))">
<xsl:value-of select="replace($date-string,'(\d{1,2}). (\d{1,2}). (\d{4})','$1\\mini$2\\mini$3')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring(replace($date-string-without-square-brackets,'(\d{1,2}). (\d{1,2}). (\d{4})','$1\\mini$2\\mini$3'),0,$opening-square-bracket),'[',substring(replace($date-string-without-square-brackets,'(\d{1,2}). (\d{1,2}). (\d{4})','$1\\mini$2\\mini$3'),$opening-square-bracket, $closing-square-bracket))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$date-string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
I finally managed to solve it with recursion. Basically I have the test whether it suits the regex dd. mm. yyyy when the brackets are removed. as this works i can now rebuild the whole string.
<xsl:function name="foo:date-repeat">
<xsl:param name="date-string" as="xs:string"/>
<xsl:param name="amount" as="xs:integer"/>
<xsl:param name="counter" as="xs:integer"/>
<xsl:choose>
<xsl:when test="substring($date-string,$counter,1) =' '">
<xsl:text>\mini</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($date-string,$counter,1)"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$counter <= $amount">
<xsl:value-of select="foo:date-repeat($date-string, $amount,$counter+1)"/>
</xsl:if>
</xsl:function>
<xsl:function name="foo:date-translate">
<xsl:param name="date-string" as="xs:string"/>
<xsl:variable name="date-string-without-square-brackets" as="xs:string" select="replace(replace($date-string,'\[',''),'\]','')"/>
<xsl:choose>
<xsl:when test="matches($date-string-without-square-brackets,'\d{1,2}. \d{1,2}. \d{4}')">
<xsl:choose>
<xsl:when test="not(contains($date-string,'['))"> <!-- Daten ohne eckige Klammer -->
<xsl:value-of select="replace($date-string,'(\d{1,2}). (\d{1,2}). (\d{4})','$1\\mini$2\\mini$3')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="foo:date-repeat($date-string, string-length($date-string),1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$date-string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
I have even expanded my solution, now the function checks tests every space ' ' if before is a dot or a dot and a bracket and afterwards is a number or a bracket and a number:
<xsl:function name="foo:date-repeat">
<xsl:param name="date-string" as="xs:string"/>
<xsl:param name="amount" as="xs:integer"/>
<xsl:param name="counter" as="xs:integer"/>
<xsl:choose>
<xsl:when test="substring($date-string,$counter,1) =' ' and ((substring($date-string,$counter -1,1) = '.' and number(substring($date-string,$counter -2,1)) = number(substring($date-string,$counter -2,1))) or (substring($date-string,$counter -2,2) = '.]' and number(substring($date-string,$counter -3,1)) = number(substring($date-string,$counter -3,1))))">
<xsl:choose>
<xsl:when test="number(substring($date-string,$counter +1,1)) = number(substring($date-string,$counter +1,1))">
<xsl:text>\mini</xsl:text>
</xsl:when>
<xsl:when test="substring($date-string,$counter +1,1) ='[' and number(substring($date-string,$counter +2,1)) = number(substring($date-string,$counter +2,1))">
<xsl:text>\mini</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($date-string,$counter,1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="substring($date-string,$counter,1) ='['">
<xsl:text>{[}</xsl:text>
</xsl:when>
<xsl:when test="substring($date-string,$counter,1) =']'">
<xsl:text>{]}</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($date-string,$counter,1)"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$counter <= $amount">
<xsl:value-of select="foo:date-repeat($date-string, $amount,$counter+1)"/>
</xsl:if>

Convert timestamp to date with XSLT

I have node like:
<item id="37" publish_time="1293829200">
How to convert #publish_time to date like dd.mm.yyyy?
I'm using libxslt
Here is a template that I wrote to convert seconds to a more readable format. You can extend it to cover your needs :
<xsl:template name="convertSecsToTimeStamp">
<xsl:param name="seconds"/>
<xsl:variable name="hours" select="floor($seconds div (60 * 60))"/>
<xsl:variable name="divisor_for_minutes" select="$seconds mod (60 * 60)"/>
<xsl:variable name="minutes" select="floor($divisor_for_minutes div 60)"/>
<xsl:variable name="divisor_for_seconds" select="$divisor_for_minutes mod 60"/>
<xsl:variable name="secs" select="ceiling($divisor_for_seconds)"/>
<xsl:choose>
<xsl:when test="$hours < 10">
<xsl:text>0</xsl:text><xsl:value-of select="$hours"/><xsl:text>hh</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$hours"/><xsl:text>hh</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$minutes < 10">
<xsl:text>0</xsl:text><xsl:value-of select="$minutes"/><xsl:text>mm</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$minutes"/><xsl:text>mm</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$secs < 10">
<xsl:text>0</xsl:text><xsl:value-of select="$secs"/><xsl:text>ss</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$secs"/><xsl:text>ss</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

left trim white space xslt 1.0

I am creating a left trim template and I have this below template:
<xsl:template name="str:left-trim">
<xsl:param name="string" select="''"/>
<xsl:variable name="tmp" select="substring($string, 1, 1)"/>
<xsl:if test="$tmp = ' '">
<xsl:variable name="tmp2" select="substring-after($string, $tmp)"/>
<xsl:choose>
<xsl:when test="$tmp2 != ''">
<xsl:call-template name="str:left-trim">
<xsl:with-param name="string" select="$tmp2"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$tmp2"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="$tmp != ' '">
<xsl:value-of select="$string"/>
</xsl:if>
</xsl:template>
if I pass an argument like this:
<xsl:variable name="str-test2">this is a america</xsl:variable>
then my template will work just fine but if I pass an argument like this below then, my template will fail. I think there is something wrong with the break(newline)
<xsl:variable name="str-test2">
this is a america
</xsl:variable>
do you have any suggestion?
This works for me. Note I didn't use the str: namespace plus I'm checking for leading newlines.
<xsl:template name="left-trim">
<xsl:param name="string" select="''"/>
<xsl:variable name="tmp" select="substring($string, 1, 1)"/>
<xsl:choose>
<xsl:when test="$tmp = ' ' or $tmp = '
'">
<xsl:call-template name="left-trim">
<xsl:with-param name="string" select="substring-after($string, $tmp)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
HTH, Axel.
Here's a solution to left-trim a string in XSLT 1.0 without using a recursive template:
<xsl:value-of select="substring($str-test2, string-length(substring-before($str-test2, substring(normalize-space($str-test2), 1, 1))) + 1)"/>