As I know there's no out of box XSLT function for advanced calculation, anyone have any idea how I can do math such as Cosine/Sin() within XSLT? The requirement is also very specific which I need the extension to be downloadable(instead of pointing to a url) so that I can download it and reference as source within my XSL script. I am unable to download EXSLT source files to try as it seems like there's an issue with that page. Can you please also provide a simple example of how to reference the source within the script and calculate something simple like:
<input>
<num1>1</num1>
<num2>1</num2>
</input>
and have the output as:
<output>
<cosOfnum1>0.54030230586</cosOfnum1>
<sinOfnum2>0.8414709848</sinOfnum2>
</output>
Thank you!
Saxon 9 (including HE, tested with 9.6, see also http://saxonica.com/html/documentation9.6/functions/math/sin.html saying "From Saxon 9.6, available in all editions.") does have out of the box support for the functions defined in https://www.w3.org/2005/xpath-functions/math/, here is an example:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="2.0">
<xsl:template match="input">
<output>
<xsl:apply-templates/>
</output>
</xsl:template>
<xsl:template match="num1">
<cosOfnum1>
<xsl:value-of select="math:cos(.)"/>
</cosOfnum1>
</xsl:template>
<xsl:template match="num2">
<sinOfnum2>
<xsl:value-of select="math:sin(.)"/>
</sinOfnum2>
</xsl:template>
</xsl:stylesheet>
I have also tested that XmlPrime 4 runs the above stylesheet correctly when using the command line option --xt30 so it also has built-in support for those functions.
Altova XMLSpy 2017 also supports the functions in the namespace xmlns:math="http://www.w3.org/2005/xpath-functions/math" out of the box but only in version="3.0" stylesheets.
As I know there's no out of box XSLT function for advanced
calculation, anyone have any idea how I can do math such as
Cosine/Sin() within XSLT?
Using the FXSL library, one can have among other things trigonometric functions, written in pure XSLT 1.0 or XSLT 2.0:
http://fxsl.sourceforge.net/articles/xslCalculator/The%20FXSL%20Calculator.html#The_Trigonometric_Functions
The Math modules of FXSL implement:
The wellknown trigonometric functions: sin(), cos(), tan(), cot(), sec(), csc()
Hyperbolic trigonometric functions: hsin(), hcos(), htan(), hcot(), hsec(), hcsc()
Exponential and logarithmic functions: exp(), ln(), log10(), log2(), log(), pow(), sqrt()
Solving equations of one real variable: the Newton - Raphson's method and the Binary Search method.
Inverse functions: arcsin(), arccos(), arctan(), arccot(), arcsec(), arccsc(), archsin(), archcos(), archtan(), archcot(), archsec(), archcsc(),
Related
For parsing some strings, I want to use analyze-string(), if available, and provide a slower fallback that works with XSLT 2.0. This is a quick test I did:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template name="tokenize"
use-when="not(function-available('analyze-string'))">
2.0
</xsl:template>
<xsl:template name="tokenize" version="3.0"
use-when="function-available('analyze-string')">
3.0
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="tokenize"/>
<xsl:value-of select="function-available('analyze-string')"/>
</xsl:template>
</xsl:stylesheet>
I ran this inside oXygen 15.2 with Saxon-PE/EE 9.5.1.3. Strangely, the output is
2.0
true
which indicates that the first template was included rather than the second, although its use-when attribute should have evaluated to true, as the second line of the output indicates. What went wrong?
Are there standard best practices when developing a stylesheet targeted at both 2.0 and 3.0 processors? Saxon HE accepts the stylesheet if I use the option -xsltversion:2.0 to override the version attribute on the xsl:stylesheet element. I also tried to set the version attribute to 2.0 to make overriding superfluous, but then function-available('analyze-string') will evaluate to false in Saxon PE/EE, even if I prefix it with the XPath functions namespace.
In Saxon 9.5, for reasons which now escape me, the static context for use-when expressions includes only the core XPath 2.0 functions plus a few selected XSLT functions such as element-available, system-property, and function-available; it doesn't include XPath 3.0 functions such as analyze-string, even though these are available in "ordinary" XPath expressions within the stylesheet. I suspect this reflects the state of the XSLT 3.0 specification at the time Saxon 9.5 was released in 2013. The situation will have changed in 9.6 and 9.7.
I have been trying my XSLT code in the online tool [XSLT 1.0 processor]:
http://www.freeformatter.com/xsl-transformer.html
Recently, I had to make use of xs:dateTime and hence started using the tool that uses XSLT 2.0 processor,
http://xsltransform.net/
Now, when i was trying to solve a problem, i see that i get different output for the same input XML in these two processors. The code posted here is not the real code i am working on; this is to simulate the weird output i faced.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<book>
<title></title>
</book>
<phone>apple</phone>
</items>
XSLT:
<?xml version="1.0" encoding="ISO-8859-1"?>
<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="/">
<items><xsl:apply-templates select="items/*" /></items>
</xsl:template>
<!-- ignore empty elements -->
<xsl:template match="*[not(normalize-space())]" />
<xsl:template match="book">
<newbook><xsl:apply-templates /></newbook>
</xsl:template>
<xsl:template match="title">
<newtitle><xsl:apply-templates /></newtitle>
</xsl:template>
<xsl:template match="phone">
<newphone><xsl:apply-templates /></newphone>
</xsl:template>
</xsl:stylesheet>
Output from http://xsltransform.net/ : [output 1]
<?xml version="1.0" encoding="UTF-8"?>
<items>
<newbook>
<newtitle/>
</newbook>
<newphone>apple</newphone>
</items>
Output from http://www.freeformatter.com/xsl-transformer.html : [output 2]
<?xml version="1.0" encoding="UTF-8"?>
<items>
<newphone>apple</newphone>
</items>
Expected output XML is output 2 .
Any idea why this different output behavior?
note: I looked at another SO question: Generating two different outputs for the same XSL file?, but that is different.
Edit
To add more clarity on which tool produced which output:
http://xsltransform.net/ produced output 1
http://www.freeformatter.com/xsl-transformer.html produced output 2
Update[02/10/2014] - regarding solution
Since the correct answer was first provided by Jim Garrison, that's marked as answer. However, there are other important points as well, as pointed out by others, Hence I am wrapping up all here.
<xsl:template match="*[not(normalize-space())]" />
The above template eliminates the empty nodes in both XSLT1 and XSLT2. Hence output 2 is correct
*Reason for getting output 1 from the tool - http://xsltransform.net/ :*
As #michael.hor257k pointed out, there are two templates that matches the <book> element.
The tool was using Saxon-HE 9.5.1.3, and the output 1 behavior was probably a bug that was fixed in the latest maintenance release [#Michael Kay explained well in his answer]
As #Ian Roberts mentioned in his answer, there is a concept of default priorities that are assigned to different types of templates.
Changing the template syntax to:
<xsl:template match="*[not(normalize-space())]" priority="2"/>
yields the same output in both the tools regardless of Saxon version, because we are explicitly defining the priority to the template.
Output 2 is correct. I ran your example in Oxygen/XML, using both XSLT1 and XSLT2 and got the correct results for both. Your template
<xsl:template match="*[not(normalize-space())]" />
eliminates the empty nodes in both XSLT1 and XSLT2.
Therefore the only possible conclusion is that the online tool that produced your Output 1 has a bug.
I get the correct result running with Saxon-EE 9.5.1.4; the xsltransform site is running Saxon-HE 9.5.1.3. It's probably a bug that we fixed in the latest maintenance release; I'll do some chasing to see if I can finger it.
Note that an empty <book> element matches two of your templates:
<xsl:template match="*[not(normalize-space())]" />
and:
<xsl:template match="book">
<newbook><xsl:apply-templates /></newbook>
</xsl:template>
The same thing applies to an empty <title> element. Such conflicts must be resolved by the XSLT processor, using the priorities specified in the XSLT specification.
The result you report from http://xsltransform.net/ is generated by Saxon 9.5.1 - an XSLT 2.0 engine. You will get a different result (on the same site) if you switch to an XSLT 1.0 engine (Saxon 6.5 or Xalan 2.7.1).
I don't know if the conflict resolution rules have changed in XSLT 2.0 compared to XSLT 1.0; I am getting a different result myself when using Saxon 8.9 - also an XSLT 2.0 processor. Perhaps we will be fortunate enough to hear from Michael Kay regarding this difference (I have added a Saxon tag to your question to get his attention)..
Output 2 is definitely the correct one according to both the 1.0 and 2.0 XSLT specs for the stylesheet you give in the question. However you say this is simplified when compared to your real stylesheet.
The thing that makes it work is the default priorities that are assigned to different types of templates. These are the same in both XSLT versions, and a match pattern that involves a predicate will overrule one that is just a single element name test.
However a match that involves hierarchy (e.g. match="items/book") or anything more complex than just a single element name will get the same priority as the *[....] rule by default - 0.5. If you've got any of these kinds of patterns in your real XSLT then you need to add an explicit priority higher than 0.5 to the "blank-suppressor" template.
<xsl:template match="*[not(normalize-space())]" priority="2"/>
I'm trying to do some operation on dates using XSL. I found a tutorial on IBM developerWorks with this script.
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times"
version="1.0"
>
<xsl:output method="html"/>
<!-- B -->
<xsl:variable name="now" select="date:date-time()"/>
<xsl:template match="/">
<!-- The rest of the Web site HTML material would go here -->
<xsl:call-template name="date-section"/>
</xsl:template>
<xsl:template name="date-section">
<p>This page was loaded at <xsl:text/>
<!-- C -->
<xsl:value-of select="concat(date:hour-in-day($now), ':',
date:minute-in-hour($now), ':',
date:second-in-minute($now))"/>
<xsl:text> on </xsl:text>
<xsl:value-of select="concat(date:day-in-month($now), ' ',
date:month-name($now), ' ',
date:year($now))"/>
</p>
<p>
<!-- D -->
<xsl:variable name="days-elapsed"
select="concat('-P',date:day-in-month($now),'D')"/>
<xsl:variable name="one-month-hence"
select="date:add($now, 'P1M')"/>
<xsl:variable name="next-month-start"
select="date:add($one-month-hence, $days-elapsed)"/>
<xsl:variable name="seconds"
select="date:seconds(
date:difference($now, $next-month-start)
)"/>
<xsl:text>The next month starts in </xsl:text>
<xsl:value-of select="$seconds div (3600*24)"/>
<xsl:text> days</xsl:text>
</p>
</xsl:template>
I get the following errors:
[ERROR]: Cannot find external method 'com.sun.org.apache.xalan.internal.lib.ExsltDatetime.add' (must be public).
[ERROR]: Cannot find external method 'com.sun.org.apache.xalan.internal.lib.ExsltDatetime.difference' (must be public).
[ERROR]: Cannot find external method 'com.sun.org.apache.xalan.internal.lib.ExsltDatetime.seconds' (must be public).
[ERROR]: Cannot convert data-type 'void' to 'real'.
[FATAL]: Could not compile stylesheet
Any ideas how to fix it. I'm using IntelliJ to run the xsl.
Ultimately I want to to be able to add days to a date. For some reason when I try to use xsl 2 date functions it just tells me they do not exist(And yes I do change the header to version 2 :) ). So I'm trying to make it work with a 3rd party library. The date-time() function from the http://exslt.org/dates-and-times namespace is working but I can't seam to be able to call other functions form that namespace.
the question is a bit old but the answers were, IMHO, not quite correct and my answer might help some other people stumbling upon this thread (as I just did):
The functions used are XSLT 1.0 extension functions, there are different modules (e.g. dates-and-times), each with mandatory and optional functions (and elements). See EXSLT
The issue here is that XALAN does support the module dates-and-times, but not all optional functions.
As suggested, you can surely try to find a "better" XSLT-Processor, but it might require some work to integrate. I personally use on the Linux command line xsltproc, which supports more of the dates-and-times module (try xsltproc --dumpextensions | sort for an overview).
Alternatively, you could try the approach describing how to get current date and time in XSLT 1.0. I haven't tried it myself yet (as said, xsltproc is a good enough workaround), but using a similar approach you should be able to implement what you need without having to touch your tool/java code.
For sake of completeness, my tool with the same problem is Freeplane from freeplane.org, which also uses XALAN (I guess that it's part of standard Java libraries) and fails on similar dates-and-times functions.
Hope this helps,
Eric
I don't know Xalan, so I don't know why it's failing to find these methods.
But if you want to use the XSLT 2.0 date/time functions, you need to invoke an XSLT 2.0 processor, and the obvious one for the Java environment is Saxon (current version is 9.4). Switching processor requires a little bit more than changing the version number: for example, if you are running it from the command line then you will need to use a different command.
I'm customizing a Google Search appliance, which uses XSLT to present results to the user. Our design calls for one of several images to be included randomly on the results page. Is there a way to use randomness in XSLT? (Pseudo-randomness is just fine for this application.)
Calling random templates would be fine, as would just being able to generate a random number and branch based on that.
You can generate in pure XSLT sequences of random numbers and also random permutations of the numbers in [1 .. N].
Just use the FXSL library (written in pure XSLT) for this.
This article explains the templates to use and has complete examples:
"Casting the Dice with FXSL: Random Number Generation Functions in XSLT".
Depending on your platform XSL allows inject of user code like C#. I don't recommend this. Better, I would have your XSL accept a parameter and whatever is generating your XML payload or XSLT and can also generate the random number, setting the parameter. I've done this exactly using this approach except the data came from Bing, not G.
If you use a Java based XSLT engine, this will allow you to make calls to any static method within the Java libraries, such as java.lang.Math.random(). Here is the syntax...
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="java.lang.Math"
version='1.1'>
<xsl:template match="/">
<xsl:variable name="myRandom" select="math:random()"/>
<xsl:value-of select="$myRandom"/>
</xsl:template>
</xsl:stylesheet>
If you are not averse to including libraries, there are many available such as random:random-sequence from EXSLT
If you are doing this for anything Microsoft, I found that using XSLT's function ddwrt:Random works.
I use the following to create the random number
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="RandomNumber" select="ddwrt:Random(1, $RowCount)" />
and the following to present
<xsl:for-each select="$Rows[position() = $RandomNumber]">
<xsl:value-of select="#Title" /></xsl:for-each>
Is there a way to get the current folder path from within a XSLT file?
I need it to locate other XML and XSLT files. We have different customer folders and will need to successfully find the correct files.
You can send it into the style-sheet from outside using xsl:param. Then you need to determine what the current path is when invoking the from the outside ;)
In MSXSL on Windows, you can use a script extension like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://tempuri.org/msxsl"
>
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
var fso = new ActiveXObject("Scripting.FileSystemObject");
function getCurrentPath(){
return fso.GetFolder(".").Path
}
]]>
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:getCurrentPath()"/>
</xsl:template>
</xsl:stylesheet>
Other XSL processors support similar methods to use external resources (scripting languages, function libraries etc.), so this is just an example.
Is there a way to get the current
folder path from within a xslt file?
Need it to locate other xml and xslt
files
No need for any extension functions or even parameters to do that!
Any relative URLs used in the href attribute of an <xsl:import> or <xsl:include>
instruction are resolved based on the URL of the current XSLT stylesheet -- it only needs to have an URL, which is vlearly stated as true in the question above. This is very convenient in importing/including XSLT stylesheets.
The document() function also will resolve a relative URL in a similar way, thus making any additional XML document accessible using anrelative URL.
Lastly, here is an example how this facilities are massively used in a big library of XSLT functions and templates (FXSL 2.x):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs xdt f"
>
<!--
This module contains the FXSL versions of the "standard" XPath functions
These are intended as convenience functions, so that they can be passed
as parameters to other functions (e.g. to f:zipWith())
or curried and passed as parameters (e.g. to f:map())
-->
<xsl:import href="func-curry.xsl"/>
<xsl:import href="func-compose-flist.xsl"/>
<xsl:import href="func-standardArithmeticXpathFunctions.xsl"/>
<xsl:import href="func-standardBooleanXpathFunctions.xsl"/>
<xsl:import href="func-standardStringXpathFunctions.xsl"/>
<xsl:import href="func-standardNodesXpathFunctions.xsl"/>
<xsl:import href="func-standardSequencesXpathFunctions.xsl"/>
<xsl:import href="func-standardAggregateXpathFunctions.xsl"/>
<xsl:import href="func-standardDateTimeXpathFunctions.xsl"/>
<xsl:import href="func-standardXSLTXpathFunctions.xsl"/>
<xsl:import href="func-standardAxisXpathFunctions.xsl"/>
</xsl:stylesheet>
This may work for your setup:
<xsl:value-of select="system-property('user.dir')"/>
For example,
<xsl:value-of select="document(concat(system-property('user.dir'),'/',filename,'.xml'))//title[1]"/>
no...
but you could maybe workaround the problem by using relative URLs and/or passing parameters into the stylesheet.
In most XSLT processor, you can add custom functions as extensions. For example here is Saxon's documentation how to do that.
Not AFAIK (though you could always pass it as a param to the transform), but I'm not clear why relative paths won't work for you here.