incorporating string into the when contidtion in xsl - xslt

I am trying to incorporate string into the when condition, but it does not work.
I have tried this:
<xsl:text>Salary:</xsl:text>
<xsl:for-each select="z:SalaryRecord">
<xsl:choose>
<xsl:when test="z:SalaryRecord = 'agreement'">
<xsl:value-of select="concat(' ',position(),' ',z:Type,'
')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' ',position(),' ',' ',z:Type,'(','from ',z:AmountFrom, ' to ',z:AmountTo,')','
')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
and this:
<xsl:when test="z:SalaryRecord::text() = 'agreement'">
and this
<xsl:when test="z:SalaryRecord == 'agreement'">
My XML source code:
<RequiredSalary>
<SalaryRecord>
<Type>monthly</Type>
<AmountFrom>1000</AmountFrom>
<AmountTo>2000</AmountTo>
</SalaryRecord>
<SalaryRecord>
<Type>agreement</Type>
</SalaryRecord>
</RequiredSalary>
Any idea pls?
thanks

One fix to your situation may be the following template. However, you'd have to define a namespace for the z prefix in your stylesheet. Try adding xmlns:z="http://whatever.is.your.namespace" to your XSLT stylesheet element.
<xsl:template match="z:RequiredSalary">
<xsl:for-each select="z:SalaryRecord">
<xsl:text>Salary:</xsl:text>
<xsl:choose>
<xsl:when test="z:Type = 'agreement'">
<xsl:value-of select="concat(' ',position(),' ',z:Type,'
')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' ',position(),' ',' ',z:Type,'(','from ',z:AmountFrom, ' to ',z:AmountTo,')','
')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:value-of select="'
'" />
</xsl:template>

Related

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>

embeding od condition in xsl when getting error

below is the xsl tag on which I am getting the error as i have used xsl:when intead of xsl:if , folks please advise how can I re correct it so that i do not get compilation exception while transforming the xsl again I am using xslt 1.0
<xsl:when test="abcid=dec_id">
<xsl:for-each select="$qq_Obj/ert_Period/ytr_Period">
<xsl:variable name="ABC_Rate">
<xsl:value-of select="$Sds/oht_Period/rew_Period/#vgRate" />
</xsl:variable>
<xsl:choose>
<xsl:when test="$iue_first=#vgRate">
<xsl:value-of select="'AAA'" />
</xsl:when>
<xsl:value-of select="'BBB'" />
</xsl:choose>
</xsl:for-each>
</xsl:when>
You need to enclose the "else" part of an xsl:choose in an xsl:otherwise:
<xsl:choose>
<xsl:when test="$iue_first=#vgRate">
<xsl:value-of select="'AAA'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'BBB'" />
</xsl:otherwise>
</xsl:choose>

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)"/>

How to transform a number (1,2,3, etc) into an ordinal number (1st, 2nd, 3rd, etc) using xslt

Pretty simple question, how can I transform a number (1, 2, 3, etc) into a print friendly ordinal number (1st, 2nd, 3rd, etc) using xslt?
Currently the following works for 1-20 but we may be seeing larger sets of entities getting ranked soon:
<xsl:template name="FormatRanking">
<xsl:param name="Value"></xsl:param>
<xsl:choose>
<xsl:when test="$Value = '1'">
<xsl:value-of select="$Value"/>st
</xsl:when>
<xsl:when test="$Value = '2'">
<xsl:value-of select="$Value"/>nd
</xsl:when>
<xsl:when test="$Value = '3'">
<xsl:value-of select="$Value"/>rd
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Value"/>th
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The only way I would know how to do this would be to change the xsl:when's:
<xsl:when test="$Value = '1'">
<xsl:when test="$Value = '2'">
<xsl:when test="$Value = '3'">
to (not even sure if this is correct):
<xsl:when test="$Value = '1' or $Value = '21' or $Value = '31' ...">
<xsl:when test="$Value = '2' or $Value = '22' or $Value = '33' ...">
<xsl:when test="$Value = '3' or $Value = '22' or $Value = '33' ...">
I'd like to do something similar to this Is there an easy way to create ordinals in C#? but I'm not sure if it's possible in Xslt.
At this point we only need an English solution.
Here's the solution from "Is there an easy way to create ordinals in C#?", translated to XSLT:
<xsl:template name="FormatRanking">
<xsl:param name="Value" select="0" />
<xsl:value-of select="$Value"/>
<!-- a little parameter sanity check (integer > 0) -->
<xsl:if test="
translate($Value, '0123456789', '') = ''
and
$Value > 0
">
<xsl:variable name="mod100" select="$Value mod 100" />
<xsl:variable name="mod10" select="$Value mod 10" />
<xsl:choose>
<xsl:when test="$mod100 = 11 or $mod100 = 12 or $mod100 = 13">th</xsl:when>
<xsl:when test="$mod10 = 1">st</xsl:when>
<xsl:when test="$mod10 = 2">nd</xsl:when>
<xsl:when test="$mod10 = 3">rd</xsl:when>
<xsl:otherwise>th</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
I'm not saying it's a good idea to do this in xslt, but...
<xsl:template name="FormatRanking">
<xsl:param name="Value"></xsl:param>
<xsl:choose>
<xsl:when test="substring($Value,string-length($Value)-1) = '11'">
<xsl:value-of select="$Value"/>th
</xsl:when>
<xsl:when test="substring($Value,string-length($Value)-1) = '12'">
<xsl:value-of select="$Value"/>th
</xsl:when>
<xsl:when test="substring($Value,string-length($Value)-1) = '13'">
<xsl:value-of select="$Value"/>th
</xsl:when>
<xsl:when test="substring($Value,string-length($Value)) = '1'">
<xsl:value-of select="$Value"/>st
</xsl:when>
<xsl:when test="substring($Value,string-length($Value)) = '2'">
<xsl:value-of select="$Value"/>nd
</xsl:when>
<xsl:when test="substring($Value,string-length($Value)) = '3'">
<xsl:value-of select="$Value"/>rd
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Value"/>th
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Edit: or a bit neater solution:
<xsl:template name="FormatRanking">
<xsl:param name="Value"></xsl:param>
<xsl:variable name="penultimateChar" select="substring($Value,string-length($Value)-1, 1)"/>
<xsl:variable name="lastChar" select="substring($Value,string-length($Value))"/>
<xsl:value-of select="$Value"/>
<xsl:choose>
<xsl:when test="$penultimateChar= '1'">
<xsl:text>th </xsl:text>
</xsl:when>
<xsl:when test="$lastChar = '1'">
<xsl:text>st </xsl:text>
</xsl:when>
<xsl:when test="$lastChar = '2'">
<xsl:text>nd </xsl:text>
</xsl:when>
<xsl:when test="$lastChar = '3'">
<xsl:text>rd </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>th </xsl:text>
</xsl:otherwise>
</xsl:choose>
IMO, by using regular expressions (XSLT 2.0), this can be done more concisely:
<xsl:template name="FormatRanking">
<xsl:param name="Value"/>
<xsl:choose>
<xsl:when test="matches(string($Value), '.+[^1][123]$')">
<xsl:value-of select="replace(replace(replace(string($Value), '1$', '1st'), '2$', '2nd'), '3$', '3rd')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(string($Value), 'th')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This checks for applicability of the special rule before using a regular expression which recognises number strings ending on 1/2/3, excluding 11/12/13. Only then special handling is applied. Otherwise the "th" is just appended.
Please note that the $Value is converted explicitly to a string datatype before applying string operations to avoid potentially funny situations. The return value is anyway implicitly a string.
However, just as a side comment, this only works for the English language. I'd be interested in a true multilingual approach....