XSLT subtraction - xslt-1.0

I have a problem with the following XSL code.
It's really simple subtraction, but it does something strange. I know I can just use format-number, but can someone explain to me why I get 0.4299999999999997 instead of the expected 0.43?
<xsl:template match="/">
<root>
<xsl:value-of select="36.98 - 36.55"></xsl:value-of>
</root>
</xsl:template>

Read about floating - point arithmetic:
http://en.wikipedia.org/wiki/Floating_point

Related

XSL-Transformation: escape tags and keep attributes within this tag

I'm an absolute beginner concerning xsl transformation and I have a problem one of you may can help me with. I have following xml block:
<Metrics>
<Metric name="DocAmount" value="123.21" currency="GBP" type="Total"/>
<Metric name="Invoices" value="113.21" currency="GBP" type="Total"/>
<Metric name="Credit" value="10.00" currency="GBP" type="Total"/>
</Metrics>
I have to escape the "<" and ">" from the inner elements "Metric" and keep at the same time all attributes with their values => I want to have this:
<Metrics>
<Metric name="DocAmount" value="123.21" currency="GBP" type="Total"/>
<Metric name="Invoices" value="113.21" currency="GBP" type="Total"/>
<Metric name="Credit" value="10.00" currency="GBP" type="Total"/>
</Metrics>
I already searched here in stackoverflow and found a way to escape the "<" and the ">" but with my xsl template the attributes arn't copied and I get this here:
<Metrics>
<Metric></Metric>
<Metric></Metric>
<Metric></Metric>
</Metrics>
To get this I used following xsl template definition:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Metric">
<xsl:value-of select="concat('<',name(),'>',.,'</',name(),'>')" />
</xsl:template>
</xsl:stylesheet>
Can anybody help me to setup a correct xsl template doing what I want to have?
Thanks a lot in advance for your help!
As your question is tagged as XSLT 2 and these days we have XSLT 3 and the main XSLT 2.0 implementations like Saxon 9 with Saxon 9.8 or Altova with Altova 2017 or 2018 have been updated to support XSLT 3 I think the easiest and most elegant solution is to move to XSLT 3 and use the XPath 3 serialize function:
<xsl:template match="Metric">
<xsl:value-of select="serialize(.)"/>
</xsl:template>
As your comment indicates you have namespaces in your input you don't want to be serialized you can use
<xsl:template match="Metric">
<xsl:variable name="copy" as="element(Metric)"><xsl:copy-of select="." copy-namespaces="no"/></xsl:variable>
<xsl:value-of select="serialize($copy)"/>
</xsl:template>

Variable declaration in nested tag in XSLT

Could anyone Please tell what is wrong with below code,
I am not able to create nested variable, i.e. in the format $v1/v2.
but i believe these format should work.
<xsl:variable name="n" select="100"/>
<xsl:variable name="v1">
<v2>
<xsl:value-of select="$n"></xsl:value-of>
</v2>
</xsl:variable>
<xsl:if test="$v1/v2">
<message:output>
<xsl:value-of select="$v1/v2"/>
</message:output>
</xsl:if>
In XSLT 2.0 your code looks fine; in XSLT 1.0 it would fail saying that in a path expression such as $v1/v2, the value of $v1 must be a node-set rather than a result-tree-fragment. Most XSLT 1.0 processors allow you to get around this restriction by using xx:node-set($v1)/v2 where xx is bound to some suiutable namespace.
The version of XSLT depends on what XSLT processor you are using. There are one or two processors that run XSLT 1.0 or 2.0 depending on what you ask for in the xsl:stylesheet version attribute, but a processor written in the XSLT 1.0 days doesn't know how to process XSLT 2.0, and most XSLT 2.0 processors if they see version="1.0" in the stylesheet will run XSLT 2.0 in "backwards compatibility mode", which doesn't impose all the restrictions of XSLT 1.0 (like the result-tree-fragment restriction), it merely makes some constructs behave the 1.0 way (for example, xsl:value-of will only output the first node in a node sequence).
It would be much easier to help you if you told us what your code output.
I am a bit confused here, when I checked the version using <xsl:value-of select="system-property('xsl:version')" /> it gave me 2 as output.
But in my stylesheet tag it was mentioned as 1.0, so below code was not working in that.
when i changed the version to 2.0: <xsl:stylesheet version="2.0"
the same code started working.
<xsl:template match="/">
<message:ExecuteSubProcessResponse>
<xsl:variable name="n" select="100"/>
<xsl:variable name="v1">
<v2>
<xsl:value-of select="$n"></xsl:value-of>
</v2>
</xsl:variable>
<xsl:choose>
<xsl:when test="count($v1/v2)> 0">
<message:BIMStatus>
<xsl:text disable-output-escaping="no">ELIGIBLE</xsl:text>
</message:BIMStatus>
</xsl:when>
<xsl:otherwise>
<message:BIMStatus>
<xsl:value-of select="$v1/v2"/>
</message:BIMStatus>
</xsl:otherwise>
</xsl:choose>
</message:ExecuteSubProcessResponse>
</xsl:template>

Can we declare global variable and add/Remove/Check value from it?

I want to achieve
Declare global variable having no value
<xsl:variable name="IsEqual"/>
Check variable value and change according to condition
<xsl:choose>
**// Checking value equal or not**
<xsl:when test="name=$name">
<xsl:choose>
**//Checking variable value**
<xsl:when test="$IsEqual !='Unequal'">
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Equal"/>
</xsl:when>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Unequal"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="$IsEqual"/>
Expected output value of variable $IsEqual.. IF it is not possible then what is another way to achieve this? What should I use instead of variable?
"It's not a bug, it's a feature": XSLT variables are designed not to be changeable. Actually they could be named constants. Working around that is difficult, it can be done using parameters. In most cases that isn't necessary if you use the XSLT programming attempt, where the programm is driven by the data through templates.
The answer to your question is no.
Copied this (own) text from XML and Variables
#Sam: What do you want to accomplish using a global variable? Where do you want to check for equality? I have no idea what you want to do so I can only give you a general example.
Try this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<root>
<data check="value1">This is data 1</data>
<data check="value2">This is data 2</data>
<data check="value3">This is data 3</data>
</root>
with this xslt file:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="v">value2</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="root/data[#check = $v]"/>
</xsl:template>
<xsl:template match="data">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Only the second data element will show up as this one matches the global variable, which stays the same all the time. If you want different values to match with, you can put them into your data file instead using a variable and compare the different elements.
For testing just save the two files (test.xml and test.xsl) into one directory and open test.xml with your browser.
#Sam again: As you insist on changing an xslt variable I have to repeat that this can't be done. Maybe there is a way around using the environment xslt is running in. E.g. PHP, where you can pass functions into the script. I described the technique here: Can PHP communicate with XSLT?
The xslt spec says:
XSLT does not provide an equivalent to the Java assignment operator
x = "value";
because this would make it harder to create an implementation that processes a document other than in a batch-like way, starting at the beginning and continuing through to the end.
(See http://www.w3.org/TR/xslt#variables to prove my answer "no" to your question is correct :-)

Looping a variable length array with namespaces in XSLT

My previous question[1] is related to this. I found the answer for that. Now I want to loop a variable length array with namespaces. My array:
<ns:array xmlns:ns="http://www.example.org">
<value>755</value>
<value>5861</value>
<value>4328</value>
<value>2157</value>
<value>1666</value>
</ns:array>
My XSLT code:(have added the namespace in the root)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:variable name="number" select="ns:array" />
<xsl:for-each select="$number">
<xsl:value-of select="$number" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[1]https://stackoverflow.com/questions/20287219/looping-a-variable-length-array-in-xslt
IMHO you confused yourself by introducing a variable called number which actually contains a node set of value tags. Then, as a consequence you used your variable as singe item/node which does not yield the desired result (presumingly, since you did not really tell us what you want to do with the values).
Also, I think your question does not really have anything to with namespace issues as such. You just have to make sure that the namespaces in your select expressions match the namespaces in your input file.
I would suggest to do without the variable and change the way you retrieve the current value:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:for-each select="ns:array">
<!-- Inside here you can work with the `value` tag as the _current node_.
There are two most likely ways to do this. -->
<!-- a) Copy the whole tag to the output: -->
<xsl:copy-of select="." />
<!-- or b1) Copy the text part contained in the tag to the output: -->
<xsl:value-of select="." />
<!-- If you want to be on the safe side with respect to white space
you can also use this b2). This would handle the case that your output
is required not to have any white space in it but your imput XML has
some. -->
<xsl:value-of select="normalize-space(.)" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

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