Increase the value of a variable being passed to call-template - xslt

I have the following bit of xsl inside a template:
<xsl:variable name="current_x" select="position_x" />
<xsl:variable name="current_y" select="position_y" />
<xsl:if test="units_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value"><xsl:value-of select="units" /></xsl:with-param>
<xsl:with-param name="text" select="'Units'" />
</xsl:call-template>
</xsl:if>
<xsl:if test="sensor_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value"><xsl:value-of select="sensor" /></xsl:with-param>
<xsl:with-param name="text" select="'Type'" />
</xsl:call-template>
</xsl:if>
My call-template is like this:
<xsl:template name="DisplayBox">
<xsl:param name="current_x" select="0"/>
<xsl:param name="current_y" select="0"/>
<xsl:param name="value" />
<xsl:param name="text" />
<g transform="translate({$current_x},{$current_y})">
<rect x="20" y="150" width="220" height="20" fill="#FFFFFF" stroke="black" stroke-width="1" />
<text x="25" y="168" font-family="arial" font-size="20px" fill="black">
<xsl:value-of select="$value"/>
</text>
<line x1="90" y1="150" x2="90" y2="170" stroke="black" stroke-width="1" />
<text x="95" y="168" font-family="arial" font-size="20px" fill="black">
<xsl:value-of select="$text" />
</text>
</g>
</xsl:template>
This displays the value of 'value' and 'text' inside a rectangle. The thing I cannot work out how to do, however, is to not have them write on top of each other. I want to increase the current_y value if the test="xxxx_display=true. But I am at a loss of how to achieve this.
I can't work out how I can increase the value of current_y outside of the call-template.
EDIT:
There seems to be a problem in using transform translate in the call-template. It seems to ignore those values.
I have modded the code to now be:
<xsl:if test="units_display='true'">
<g transform="translate({position_x},{position_y})">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value">
<xsl:value-of select="units" />
</xsl:with-param>
<xsl:with-param name="text" select="'Units'" />
</xsl:call-template>
</g>
</xsl:if>
<xsl:if test="sensor_display='true'">
<g transform="translate({position_x},{position_y + 20})">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value">
<xsl:value-of select="sensor" />
</xsl:with-param>
<xsl:with-param name="text" select="'Type'" />
</xsl:call-template>
</g>
</xsl:if>
But, I don't want to hard-code 'position_y + 20'. I would like the 2nd value to be at position_y if the first value display was not true, but the 2nd value to be at position_y + 20 if the first value display was true. This must be possible somehow I would hope.

By the way, don't do this:
<xsl:with-param name="value"><xsl:value-of select="sensor" /></xsl:with-param>
when you mean this:
<xsl:with-param name="value" select="sensor" />
It's not only verbose, it's also incredibly inefficient: instead of simply passing a reference to a value, you are constructing a temporary tree containing a text node that holds a copy of the value. Creating new trees is an expensive operation.

Simply pass the the parameters current_x and current_y with the adjusted values like this:
<xsl:if test="units_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value"><xsl:value-of select="units" /></xsl:with-param>
<xsl:with-param name="text" select="'Units'" />
<xsl:with-param name="current_x" select="position_x"/>
<xsl:with-param name="current_y" select="position_y + 100"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="sensor_display='true'">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value"><xsl:value-of select="sensor" /></xsl:with-param>
<xsl:with-param name="text" select="'Type'" />
<xsl:with-param name="current_x" select="position_x"/>
<xsl:with-param name="current_y" select="position_y + 200"/>
</xsl:call-template>
</xsl:if>
EDIT: If you want to go with the second approach, try to change the sensor_display part to:
<xsl:if test="sensor_display='true'">
<xsl:variable name="offset">
<xsl:choose>
<xsl:when test="units_display='true'">20</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<g transform="translate({position_x},{position_y + $offset})">
<xsl:call-template name="DisplayBox">
<xsl:with-param name="value">
<xsl:value-of select="sensor" />
</xsl:with-param>
<xsl:with-param name="text" select="'Type'" />
</xsl:call-template>
</g>
</xsl:if>
BTW, if you rephrase your question like this, it's better to start a new question.

Related

How can I check how many times an element was created and create it n number of times

I want to create an element(Parameter) n number of times. I used the following method to create an element "Parameter" which contain the value from the Split template. Each recursion create the element "Parameter". How can I check how many time was the element "Parameter" created and and if it was less than n then how can I create it n number of times with no values.
<xsl:call-template name="Split">
<xsl:with-param name="text" select="Set string "{attribute}" value "{stringValue}"" />
</xsl:call-template>
<xsl:template name="Split">
<xsl:param name="text" select="''" />
<xsl:variable name="tag" select="substring-before(substring-after($text, '"'), '"')" />
<xsl:variable name="tail" select="substring-after($text, '"')" />
<xsl:choose>
<xsl:when test="$tag != ''">
<xsl:element name = "Paramter">
<xsl:value-of select = "$tag"/>
</xsl:element>
<!--recursive step start: process the remainder of the string -->
<xsl:call-template name="Split">
<xsl:with-param name="text" select="$tail" />
</xsl:call-template>
<!--recursive step end: process the remainder of the string -->
</xsl:when>
</xsl:choose>
</xsl:template>
the Output (for n=9) should look something like this,
<Parameter>attribute</Parameter>
<Parameter>value</Parameter>
<Parameter>StringValue</Parameter>
<Parameter></Parameter>
<Parameter></Parameter>
<Parameter></Parameter>
<Parameter></Parameter>
<Parameter></Parameter>
<Parameter></Parameter>
If you call the template like this:
<xsl:call-template name="Split">
<xsl:with-param name="text" select="'Set string "{attribute}" value "{stringValue}"'" />
<xsl:with-param name="n" select="9" />
</xsl:call-template>
and adjust it so:
<xsl:template name="Split">
<xsl:param name="text"/>
<xsl:param name="n"/>
<xsl:if test="$n > 0">
<Parameter>
<xsl:value-of select="substring-before(substring-after($text, '"'), '"')" />
</Parameter>
<!--recursive call -->
<xsl:call-template name="Split">
<xsl:with-param name="text" select="substring-after($text, '"')" />
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Then the result will be:
<Parameter>{attribute}</Parameter>
<Parameter> value </Parameter>
<Parameter>{stringValue}</Parameter>
<Parameter/>
<Parameter/>
<Parameter/>
<Parameter/>
<Parameter/>
<Parameter/>
Note that this exits after 9 iterations. If the string has more than 9 tokens, only the first 9 will appear in the output.

Increment Variable count in for-each in XSLT 1.0

I want to Increment variable in for-each loop. Here is my code.
<xsl:variable name="i" select="1" />
<xsl:variable name="oddEven" select="1" />
<xsl:for-each select="//ProfileBR">
<xsl:variable name="j" select="$i + 1" />
sharad j :: <xsl:value-of select="$j"></xsl:value-of>
<xsl:variable name="iBR" select="substring(//BRValue,$i,1)" />
<xsl:variable name="jBR" select="substring(//BRValue,$j,1)" />
<xsl:if test="$iBR='1' or $jBR='1'">
<xsl:choose>
<xsl:when test="$oddEven='1'">
<tr class="sbListOddCell">
<xsl:call-template name="JobInfoSection">
<xsl:with-param name="ii" select="$i"/>
<xsl:with-param name="jj" select="$j"/>
<xsl:with-param name="iiBR" select="$iBR"/>
<xsl:with-param name="jjBR" select="$jBR"/>
</xsl:call-template>
</tr>
<xsl:variable name="oddEven" select="0" />
</xsl:when>
<xsl:otherwise>
<tr class="sbListEvenCell">
<xsl:call-template name="JobInfoSection">
<xsl:with-param name="ii" select="$i"/>
<xsl:with-param name="jj" select="$j"/>
<xsl:with-param name="iiBR" select="$iBR"/>
<xsl:with-param name="jjBR" select="$jBR"/>
</xsl:call-template>
</tr>
<xsl:variable name="oddEven" select="1" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:variable name="i" select="$j + 1" />
</xsl:for-each>
I want to increment i and j in every iteration but it ends up with 3 and 2 respectively after each iteration.
How can I increment i and j.
Thanks,
Sharad
Use position() to get the count of the iteration inside the for-each like this:
<xsl:variable name="j" select="$i + position()" />

Context error on for-each on tokenize variable

I am using XSLT 2.0 and have a variable who contains dates separated by comma. I try to tokenize this variable in a for-each but in execution, I have the error: "Cannot select a node here: the context item is an atomic value"
Here is my code:
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
...
The template dayOfMonth returns the days for the month given in parameters.
I don't understand what is wrong in my code, could you please help me?
Thanks.
Assuming you have something like
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
<xsl:value-of select="foo[date = $dateJour]"/>
you would get the error you describe, to avoid that you would need to store the context node outside of the for-each in a variable as in
<xsl:variable name="datesMois">
<xsl:call-template name="dayOfMonth">
<xsl:with-param name="pDay" select="01" />
<xsl:with-param name="pMonth" select="/workfile/query/#month" />
<xsl:with-param name="pYear" select="/workfile/query/#year" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="currentstartdate" select="substring-before(., 'T')" />
<xsl:variable name="context" select="."/>
<xsl:for-each select="tokenize($datesMois,',')">
<xsl:variable name="dateJour" select="." />
<xsl:value-of select="$context/foo[date = $dateJour]"/>
I had to guess how your code might look that causes the error, if you still have problems then post the exact line of your code that causes the error.

How to write a CSV-parser using XSLT 1.0?

I need to make a CSV-parser using XSLT 1.0. I have tried a recursive approach, but I can't seem to match the line endrings, so the input to the printLine-template is always empty.
<xsl:template match="/">
<xsl:call-template name="printLine">
<xsl:with-param name="line">
<xsl:value-of select="substring-before(//csvText, '\n')"/>
</xsl:with-param>
<xsl:with-param name="remaining">
<xsl:value-of select="substring-after(//csvText, '\n')"/>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="printLine">
<xsl:param name="line"/>
<xsl:param name="remaining"/>
<xsl:value-of select="$line"/><br />
<xsl:if test="remaining != ''">
<xsl:call-template name="printLine">
<xsl:with-param name="line">
<xsl:value-of select="substring-before($remaining, '\n')"/>
</xsl:with-param>
<xsl:with-param name="remaining">
<xsl:value-of select="substring-after($remaining, '\n')"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
I found a solution to this:
<xsl:variable name="ls"><xsl:text>
</xsl:text></xsl:variable>
<xsl:variable name="fs"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="printLine">
<xsl:with-param name="line" select="substring-before(//csvText, $ls)"/>
<xsl:with-param name="remaining" select="substring-after(//csvText, $ls)"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="printLine">
<xsl:param name="line"/>
<xsl:param name="remaining"/>
<xsl:call-template name="printFields">
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
<xsl:if test="$remaining != ''">
<xsl:call-template name="printLine">
<xsl:with-param name="line" select="substring-before($remaining, $ls)"/>
<xsl:with-param name="remaining" select="substring-after($remaining, $ls)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="printFields">
<xsl:param name="line"/>
<!-- render each line and access each field using the getFieldByIndex-template. Example: -->
<div>
<h3>
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="1"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
</h3>
<p>
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="4"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
</p>
</div>
</xsl:template>
<xsl:template name="getFieldByIndex">
<xsl:param name="index"/>
<xsl:param name="line"/>
<xsl:choose>
<xsl:when test="$index > 0">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$index -1"/>
<xsl:with-param name="line" select="substring-after($line, $fs)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($line,$fs)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The line- and field separators are stored in the ls and fs variables. This example traverses a tab-serparated file. The printFields-template has to be customized for each use.

How do I do a str:replace in XSLT/XPATH 1.0?

In XPATH 2.0 there is a function that allows me to replace a substring in a string with another string. I'd like to do this using xalan. Unfortunately, it doesn't support the EXSLT method str:replace and it only uses XSLT 1.0 stylesheets. Including the function from exslt.org doesn't seem to work. If I try using the function style, it complains that it can't find str:replace. If I try using the template style, it complains that it can't find node-set, even though it is supported. translate is useless since it's just a character swap. Any ideas?
You can write your own function which can immitate xslt 2.0 replace :
<xsl:template name="replace">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="replace">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
If you call it like this :
<xsl:variable name="replacedString">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="'This'" />
<xsl:with-param name="replace" select="'This'" />
<xsl:with-param name="by" select="'That'" />
</xsl:call-template>
Your resulting $replacedString will have the value "That"