472,986 Members | 2,907 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,986 software developers and data experts.

XSLT: Generating a format mask string based on the content of a node?

I want to use the format-number function to output
a number with a specific number of decimals, based on the content
of a node... Is there any smart way to generate differnet strings
based on a node-value?

if decimals = 0, I want "###,###"
decimals = 1, I want "###,###.0"
decimals = 2, I want "###,###.00"
decimals = n, I want "###,###.000..n"

Today I'm using <xsl:choose>, but that is limited to
hand-coding the alternatives.

I have the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Transform.xslt"?>
<root>
<valuedef>
<value>7</value>
<decimals>2</decimals>
</valuedef>
<valuedef>
<value>42</value>
<decimals>3</decimals>
</valuedef>
</root>

And I transform it like this:

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
<xsl:apply-templates select="/root/valuedef" />
</xsl:template>

<xsl:template match="valuedef">
<value>
<xsl:variable name="tall" select="value"/>
<xsl:variable name="maske">
<xsl:choose>
<xsl:when test="decimals[.='0']"###,### </xsl:when>
<xsl:when test="decimals[.='1']"###,###.0</xsl:when>
<xsl:when test="decimals[.='2']"###,###.00</xsl:when>
<xsl:when test="decimals[.='3']"###,###.000</xsl:when>
<xsl:otherwise###,### </xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select='format-number($tall, $maske)' />
</value>
</xsl:template>
</xsl:stylesheet>

TIA...

--
Dag.
Mar 9 '07 #1
7 8668
Your question is really that you want a better solution for
<xsl:choose>
<xsl:when test="decimals[.='0']"###,### </xsl:when>
<xsl:when test="decimals[.='1']"###,###.0</xsl:when>
<xsl:when test="decimals[.='2']"###,###.00</xsl:when>
<xsl:when test="decimals[.='3']"###,###.000</xsl:when>
</xsl:choose>
The traditional quick-and-dirty answer involves using the value to
control the length of a substring extraction from ".000000000000000",
and appending that to ###,###. (A bit more work is needed to suppress
the decimal point when the value is 0, but you get the idea.) The upper
limit is however many zeros you provide in the literal string, but
realistically your floating-point system also has accuracy limits so
asking for too high a precision's not useful anyway.

The completely general answer is a recursive named-template with
parameter (in lieu of counter loop), which appends a zero each time the
count is advanced.

--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
Mar 9 '07 #2
On Mar 9, 2:02 pm, "Dag Sunde" <m...@dagsunde.comwrote:
I want to use the format-number function to output
a number with a specific number of decimals, based on the
content of a node... Is there any smart way to generate
differnet strings based on a node-value?

<xsl:choose>
<xsl:when test="decimals[.='0']"###,### </xsl:when>
<xsl:when test="decimals[.='1']"###,###.0</xsl:when>
<xsl:when test="decimals[.='2']"###,###.00</xsl:when>
<xsl:when test="decimals[.='3']"###,###.000</xsl:when>
<xsl:otherwise###,### </xsl:otherwise>
</xsl:choose>
Divide and conquer.

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="valuedef">
<xsl:variable name="fmt">
<xsl:apply-templates select="decimals"/>
</xsl:variable>
<xsl:value-of select="format-number(value,$fmt)"/>
</xsl:template>
<xsl:template match="decimals">
<xsl:text>###,###.</xsl:text>
<xsl:call-template name="dec"/>
</xsl:template>
<xsl:template name="dec">
<xsl:param name="n" select="."/>
<xsl:choose>
<xsl:when test="$n &lt; 2">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="f" select="floor($n div 2)"/>
<xsl:call-template name="dec">
<xsl:with-param name="n" select="$f"/>
</xsl:call-template>
<xsl:call-template name="dec">
<xsl:with-param name="n" select="$n - $f"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

--
Pavel Lepin

Mar 9 '07 #3
Dag Sunde wrote:
I want to use the format-number function to output
a number with a specific number of decimals, based on the content
of a node... Is there any smart way to generate differnet strings
based on a node-value?

if decimals = 0, I want "###,###"
decimals = 1, I want "###,###.0"
decimals = 2, I want "###,###.00"
decimals = n, I want "###,###.000..n"
<snipped/>

Thank you both, Joe and Pavel!

Now I can get a little more flexibility...

--
Dag.

Mar 9 '07 #4
For the unconstrained solution in XSLT 2.0 one would simply use:

<xsl:value-of separator="" select=
"'###,###', if(decimals gt 0) then '.' else (), f:repeat('0',
decimals)"/>

where f:repeat is defined very simply in FXSL 2.0 as:

<xsl:function name="f:repeat" as="item()+">
<xsl:param name="pThis" as="item()"/>
<xsl:param name="pTimes" as="xs:integer"/>

<xsl:for-each select="1 to $pTimes">
<xsl:sequence select="$pThis"/>
</xsl:for-each>
</xsl:function>
For an efficient solution of the string-allocation problem in XSLT 1.0 see
something I published many years ago, which since then was used in the
implementation of the EXSLT str:padding() function:

http://sources.redhat.com/ml/xsl-lis.../msg01040.html

Hope this helped.
Cheers,
Dimitre Novatchev
"Dag Sunde" <me@dagsunde.comwrote in message
news:45***********************@news.wineasy.se...
>I want to use the format-number function to output
a number with a specific number of decimals, based on the content
of a node... Is there any smart way to generate differnet strings
based on a node-value?

if decimals = 0, I want "###,###"
decimals = 1, I want "###,###.0"
decimals = 2, I want "###,###.00"
decimals = n, I want "###,###.000..n"

Today I'm using <xsl:choose>, but that is limited to
hand-coding the alternatives.

I have the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Transform.xslt"?>
<root>
<valuedef>
<value>7</value>
<decimals>2</decimals>
</valuedef>
<valuedef>
<value>42</value>
<decimals>3</decimals>
</valuedef>
</root>

And I transform it like this:

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
<xsl:apply-templates select="/root/valuedef" />
</xsl:template>

<xsl:template match="valuedef">
<value>
<xsl:variable name="tall" select="value"/>
<xsl:variable name="maske">
<xsl:choose>
<xsl:when test="decimals[.='0']"###,### </xsl:when>
<xsl:when test="decimals[.='1']"###,###.0</xsl:when>
<xsl:when test="decimals[.='2']"###,###.00</xsl:when>
<xsl:when test="decimals[.='3']"###,###.000</xsl:when>
<xsl:otherwise###,### </xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select='format-number($tall, $maske)' />
</value>
</xsl:template>
</xsl:stylesheet>

TIA...

--
Dag.


Mar 10 '07 #5
Dimitre Novatchev wrote:
For the unconstrained solution in XSLT 2.0 one would simply use:

<xsl:value-of separator="" select=
"'###,###', if(decimals gt 0) then '.' else (), f:repeat('0',
decimals)"/>

where f:repeat is defined very simply in FXSL 2.0 as:

<xsl:function name="f:repeat" as="item()+">
<xsl:param name="pThis" as="item()"/>
<xsl:param name="pTimes" as="xs:integer"/>

<xsl:for-each select="1 to $pTimes">
<xsl:sequence select="$pThis"/>
</xsl:for-each>
</xsl:function>
For an efficient solution of the string-allocation problem in XSLT
1.0 see something I published many years ago, which since then was
used in the implementation of the EXSLT str:padding() function:

http://sources.redhat.com/ml/xsl-lis.../msg01040.html

Hope this helped.
Now *That* was elegant!

Thanks...

--
Dag.
Mar 10 '07 #6
Dag Sunde wrote:
Dimitre Novatchev wrote:
>For the unconstrained solution in XSLT 2.0 one would simply use:

<xsl:value-of separator="" select=
"'###,###', if(decimals gt 0) then '.' else (), f:repeat('0',
decimals)"/>

where f:repeat is defined very simply in FXSL 2.0 as:

<xsl:function name="f:repeat" as="item()+">
<xsl:param name="pThis" as="item()"/>
<xsl:param name="pTimes" as="xs:integer"/>

<xsl:for-each select="1 to $pTimes">
<xsl:sequence select="$pThis"/>
</xsl:for-each>
</xsl:function>
For an efficient solution of the string-allocation problem in XSLT
1.0 see something I published many years ago, which since then was
used in the implementation of the EXSLT str:padding() function:

http://sources.redhat.com/ml/xsl-lis.../msg01040.html

Hope this helped.
Now *That* was elegant!
....Only to discover that there is now version of msxml that supports
XSLT 2.0...

Oh, well...

--
Dag.

Mar 10 '07 #7
>Now *That* was elegant!
>>

...Only to discover that there is now version of msxml that supports
XSLT 2.0...

Oh, well...
If one does have to work in an Microsoft XML/XSLT environment and wants to
use XSLT 2.0, then a good choice is Saxon.NET.
Cheers,
Dimitre Novatchev.

"Dag Sunde" <me@dagsunde.comwrote in message
news:45***********************@news.wineasy.se...
Dag Sunde wrote:
>Dimitre Novatchev wrote:
>>For the unconstrained solution in XSLT 2.0 one would simply use:

<xsl:value-of separator="" select=
"'###,###', if(decimals gt 0) then '.' else (), f:repeat('0',
decimals)"/>

where f:repeat is defined very simply in FXSL 2.0 as:

<xsl:function name="f:repeat" as="item()+">
<xsl:param name="pThis" as="item()"/>
<xsl:param name="pTimes" as="xs:integer"/>

<xsl:for-each select="1 to $pTimes">
<xsl:sequence select="$pThis"/>
</xsl:for-each>
</xsl:function>
For an efficient solution of the string-allocation problem in XSLT
1.0 see something I published many years ago, which since then was
used in the implementation of the EXSLT str:padding() function:

http://sources.redhat.com/ml/xsl-lis.../msg01040.html

Hope this helped.
Now *That* was elegant!

...Only to discover that there is now version of msxml that supports
XSLT 2.0...

Oh, well...

--
Dag.

Mar 10 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Sergio del Amo | last post by:
Hi, I use the xslt functions provided by php. I am running in my computer the package xampp(www.apachefriends.org) which includes php/apache/mysql .. In this package the php includes the sablotron...
4
by: titanandrews | last post by:
Hi, I have ran into a situation that I think should be possible, but I am fairly new to XSLT so maybe not. Suppose I have the following document <ROOT> <FOO name="A"> <CHILD name="B"/>...
12
by: Keith Chadwick | last post by:
I have a fairly hefty XSLT file that for the sake of debugging and clarity I wish to split into some separate sub-templates contained within the same file. The master template calls an...
4
by: David S. Alexander | last post by:
How can I do simple subtraction in an XSLT. I want to read a few attribute values from an XML document, calculate their difference, and transform that value to an attribute in the XML output...
3
by: Ian Roddis | last post by:
Hello, I want to embed SQL type queries within an XML data record. The XML looks something like this: <DISPLAYPAGE> <FIELD NAME="SERVER" TYPE="DROPDOWN"> <OPTION>1<OPTION> <OPTION>2<OPTION>...
3
by: abhishek.smu | last post by:
Given an XML like: <root> <node>8</node> <node>21</node> <node>-7</node> <node>13</node> <node>43</node> <node>2</node> </root>
3
by: super.raddish | last post by:
Greetings, I am relatively new to, what I would call, advanced XSLT/XPath and I am after some advice from those in the know. I am attempting to figure out a mechanism within XSLT to compare the...
11
by: =?ISO-8859-1?Q?Jean=2DFran=E7ois_Michaud?= | last post by:
Context: I'm trying to compare XML tree fragments and I'm doing so by outputting the attributes of each element in the tree and outputting it to a string then normalizing the strings. Then I'm...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
4
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.