XSLT decimal-format causes exception - formatting

I am trying to use the xslt:decimal-format element, but I get the same error message whether I use my own code or the example code provided by w3schools.com. This is the w3 sample code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:decimal-format name="euro" decimal-separator="," grouping-separator="."/>
<xsl:template match="/">
<xsl:value-of select="format-number(26825.8, '#,###.00', 'euro')"/>
</xsl:template>
</xsl:stylesheet>
And this is the XsltException it produces when I run it in Visual Studio 2010:
"Format '#,###.00' cannot have zero digit symbol after digit symbol after decimal point."
What's wrong on my side that causes this error?

You have changed the decimal format, called "euro" so that a valid number looks like this "1.232,99" (one thousand, two hundred and thirty two, point nine-nine in words). This does not match the format you have requested which is "#,###.00".
Change your format-number pattern to "#.###,00"

Related

XSLT: variables and "empty" labels

I have an XML datafile containing among other things a string of arbitrarily many comma separated values. I want those values to be displayed in a web browser as a list with one value per line. So I wrote an XSLT template that takes this string, displays the first value followed by a linebreak tag (<br/>), properly name-spaced, and resources with the remainder of the string. In effect, the commas are being replaced by HTML <br/> tags.
Now, when I store the result of calling that template in a xsl:variable, and display that through xsl:value-of, then the HTML tags disappear: what is shown is the string minus the commas.
When I display the result directly by having the xsl:call-template in place of the xsl:value-of, all is fine, and the values appear in a list.
So, what's going on?
Is this behavior an implementation artifact, or is it standard XSLT?
Use xsl:copy-of instead of xsl:value-of if you want to output nodes (like your br elements), xsl:value-of creates a simple text node with the string value(s) selected.
Here is an example that shows the difference between xsl:value-of and xsl:copy-of, you will note that it is not the use of the variable with newly created br elements that makes the difference, it is simply the use of xsl:value-of that creates a text() node with the string conversion of the selection:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>
<xsl:variable name="var">Phrase 1.<br/>Phrase 2.<br/>Phrase 3.</xsl:variable>
<xsl:template match="/">
<html>
<head>
<title>.NET XSLT Fiddle Example</title>
</head>
<body>
<section>
<h1>Example 1: value-of</h1>
<xsl:value-of select="$var"/>
</section>
<section>
<h1>Example 2: copy-of</h1>
<xsl:copy-of select="$var"/>
</section>
<xsl:apply-templates select="//p"/>
<xsl:apply-templates select="//p" mode="copy-of"/>
</body>
</html>
</xsl:template>
<xsl:template match="p">
<section>
<h1>Example 1: value-of</h1>
<xsl:value-of select="."/>
</section>
</xsl:template>
<xsl:template match="p" mode="copy-of">
<section>
<h1>Example 1: copy-of</h1>
<xsl:copy-of select="."/>
</section>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gWmuiJy/1
Output is
Example 1: value-of
Phrase 1.Phrase 2.Phrase 3.
Example 2: copy-of
Phrase 1.
Phrase 2.
Phrase 3.
Example 1: value-of
Line 1.Line 2.Line 3.
Example 1: copy-of
Line 1.
Line 2.
Line 3.
It seems that you hit the boundaries of the RTF ("Result tree fragment"):
When you use an XML fragment to initialize a variable or a parameter, then the variable or parameter is of the
"result tree fragment" datatype. This is an XSLT 1.0 specific datatype [just like node-set, but slightly different].
A result tree fragment is equivalent to a node-set that contains just the root node.
You cannot apply operators like "/", "//" or predicate on a result tree fragments. They are only applicable for node-set datatypes.
[...]
a) In XSLT 1.0
The resolution of this is to convert the result tree fragment into a node-set. I am not aware of any oracle specific xpath extension functions that can do this trick for you.
You could use EXSLT to achieve this.
b) Use XSLT 2.0
You can code your transformations in XSLT 2.0. XSLT 2.0 deprecates ResultTreeFragments i.e. if you are modeling an XSLT 2.0 transformation, and you create a variable or a parameter that holds a tree fragment, it is implicitly a node sequence.
So without using an XSLT version greater than 1, you're out of luck. So better use XSLT-2.0 or 3.0 to solve this problem.
Is this behavior an implementation artifact, or is it standard XSLT?
It is standard for XSLT-1.0, but not for XSLT-2.0+.

XSLT 1 - How can I replace '&' with '&' in XML file?

I need to find solution to fix by using XSLT 1! Most of sent XML files well formatted and someone make mess by adding characters (& < >. . .). Any way to do replace this on my side? I tried XSLT 2 and Replace function does not work as I use XSLT processor from Microsoft
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
exclude-result-prefixes="xs saxon"
version="2.0">
<xsl:param name="path" select="'file:///E:/foo.xml'"></xsl:param>
<xsl:template match="/">
<xsl:copy-of select="unparsed-text($path)"></xsl:copy-of>
<xsl:copy-of select="saxon:parse(replace(unparsed-text($path), '&', '&amp;'))"/>
</xsl:template>
</xsl:stylesheet>
Any other suggestion how to solve this issue. for example I have input XML file like:
<?xml version="1.0" encoding="UTF-8"?>
<name>Stack & Exchange</name>
And is fail on '&' character.
Please advice!
Thank you
Conclusion
Two observations
XSLT requires at least a well formed XML document at the input, so I can't use it to correct invalid XML
(it is an XML transformation language)
in order to use replace or escape invalid characters of XML on input I need to make sure that I use an XSLT 2.0 processor
(I use Microsoft processor XSLT 1.0)
I see two options
If I receive an error on input, investigate and validate manually and send back the error message. - THIS IS I TRIED TO AVOID! (Use text tools like notepad++, excel to find an issue).
write a correcting parser in the .net language to fix before loading as XML

Handling 0x19 in XSLT 1.0

I have encountered a problem when input xml contains the character 0x19. I have created a demo xslt to reproduce the issue.
My demo xslt looks like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="param1"/>
<xsl:template match="/">
<Value>
<xsl:value-of select="$param1"/>
</Value>
</xsl:template>
</xsl:transform>
I am passing the character 0x19 as param1. The below output gets generated.
<Value></Value>
which is an invalid xml. How can I get it right?
You are correct that
<Value></Value>
is not well-formed XML 1.0 - XML 1.0 does not allow any control characters below U+0020 except U+0009 (tab), U+000A (LF) and U+000D (CR), not even when expressed as numeric character references, so it is simply not possible to include that character in an XML 1.0 document. The processor is wrong to produce that output, it should raise an error to complain that you've tried to insert an illegal character in the output.
However it is well formed XML 1.1, which allows control characters as &# references but not as literals. If your processor supports this (and the donwnstream components that will be receiving your output support it too) then it may be sufficient to add version="1.1" to the xsl:output instruction
<xsl:output method="xml" indent="yes" version="1.1"/>
to tell it to output XML 1.1 instead of XML 1.0.

Getting particular substring using xslt1.0

I have a string as below.
<freeForm>
<text>mnr.getValue().put("xyz","pqr");</text>
</freeForm>
From the above xml portion i need to get the string xyz.
Please provide pointers to achieve the same using xslt1.0.
Use this XPath expression:
substring-before(
substring-after(/*/*, &apos;"&apos;),
&apos;"&apos;
)
Here is a short, complete XSLT transformation that evaluates this XPath expression and outputs the result of evaluating it:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select=
'substring-before(
substring-after(/*/*, &apos;"&apos;),
&apos;"&apos;
)'/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<freeForm>
<text>mnr.getValue().put("xyz","pqr");</text>
</freeForm>
the wanted, correct result is produced:
xyz

XSLT 1.0 amount fields have to have at least 2 decimals

I have two xmls.There is a amount field which can contains values like 54.2,54.23,54.234,54.234567.
Would someone please tell me how can I make sure that atleast two decimal places will appear in the output xml.Currently 54.2 gets converted to 54,2 , but I want it to be 54,20
You can use the format-number() function to convert a number into a string in a given format.
At least two decimal places will be appeared if you use this "#.00##########" format string.
If you have an xml file which can contains values like 54.2,54.23,54.234,54.234567:
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<price>54.2</price>
<price>54.23</price>
<price>54.234</price>
<price>54.234567</price>
</catalog>
You can convert the numbers with an xslt like this to get at least two decimal places
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="/catalog/price">
<xsl:value-of select='format-number(., "#.00##########")'/><br />
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Then the output:
54.20
54.23
54.234
54.234567