i'm trying to use the ubuntu cli version of xalan:
Xalan version 1.10.0
Xerces version 2.8.0
My problem is how to kick in with date functions. I tryed like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="date">
<xsl:import href="date/date.xsl" />
<xsl:output method="text" indent="yes" />
date: <xsl:value-of select="date:date()" />
</xsl:stylesheet>
It gives me back this message:
XSLException Type is: XalanXPathException
Message is: The function number 'http://exslt.org/dates-and-times:date' is not available. (file:///home/user/test.xsl, line x, column y)
What files or what do i need to change to make those date functions work?
You need to use a later version of Xalan.
From the Xalan J.2.7.1 documentation:
EXSLT extensions
Xalan-Java supports the EXSLT
initiative to provide a set of
standard extension functions and
elements to XSLT users. Xalan-Java
includes implementations for the
following EXSLT extension modules:
EXSLT common functions EXSLT math
functions EXSLT set functions
EXSLT date-and-time functions
EXSLT dynamic functions
EXSLT string functions
The EXSLT func:function and
func:result elements (see EXSLT -
func:function)
The documentation shows that it has built-in beta implementations for that subset, however it does not say you cannot import and use the functions from exslt.org. Why can't you? Does Xalan-c++ not support importing functions?
Note that, I was able to get the templates working. Just not the functions.
From http://xml.apache.org/xalan-c/extensionslib.html
Xalan-C++ includes beta
implementations for functions in four
of the EXSLT namespaces (some are
calls to extension already in the
Xalan namespace).
And from http://xml.apache.org/xalan-c/apiDocs/XalanEXSLTDateTimeImpl_8hpp.html, it looks like only date:date-time() have been implemented.
Related
I am running a Java application which is supposed to do some XSLT processing based on javax.xml.transform.Transformer. I developed it on an older notebook using java-7-openjdk-amd64.
When I run it on another machine with java-8-openjdk-amd64 installed the Transformer throws the following exception:
javax.xml.transform.TransformerConfigurationException: Failed to
compile stylesheet. 1 error detected.
XPST0017: XPath syntax error [...]
Cannot find a matching 1-argument function named {http://xml.apache.org/xslt/java}java.text.SimpleDateFormat.new()
at net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:176)
at net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:139)
at net.sf.saxon.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:91)
The xsl file looks like this (leaving out unimportant details):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" exclude-result-prefixes="java">
<xsl:template match="/">
<html>
<body>
<h1>Test Report</h1>
<h2>Test run</a> at
[<xsl:value-of
select="java:format(java:java.text.SimpleDateFormat.new('dd.MM.yyyy HH:mm:ss'), java:java.util.Date.new())" />]
</h2>
So the Transformer obviously has a problem with invoking SimpleDateFormat, but why? I could not find any information about this in respect to Java7 vs. Java8. I even copied the Jar file compiled with Jdk7 an and ran it on the other machine. Same problem, so it seems to be a runtime issue.
There are some Q+A on SO about java and XSLT but nothing turned out to be useful for me.
It turned out be that this declaration <xsl:stylesheet version="2.0" does not ensure that XSLT v2.0 is actually used. javax.xml.transform.Transformer "secretly" used XSLT v1.0 on the old machine (with java-7-openjdk-amd64) and XSLT v2.0 with Saxon v9.1.0 on the other machine (with java-8-openjdk-amd64).
The dependency was set by a maven pom.xml at compile time. But apparently this had no effect when running it with Jre7. I could have noticed it by looking at the stack trace (net.sf.saxon.TransformerFactoryImpl) but since there were no errors before, I was not aware of any specific TransformerFactory implementation.
I'm trying to use Saxon 9.1.0.8 HE to apply (recent) Docbook XSL, and getting this:
Don't know how to chunk with SAXON 9.1.0.8 from Saxonica
Processing terminated by xsl:message at line 46 in chunker.xsl
Docbook XSL source claims that:
<!-- This stylesheet works with XSLT implementations that support -->
<!-- exsl:document, saxon:output, or Xalan's redirect:write -->
<!-- Note: Only Saxon 6.4.2 or later is supported. -->
...and a visit to line 46 mentioned in the error message (which tests for element-available('saxon:output')), and to Saxon documentation, shows that the root of the problem is that Saxon no longer recognizes the saxon:output extension.
This source suggests that to make Saxon 9.4 compatible with XSLT 1.0 (which is what the stylesheets are in, and what saxon:output used to be good for in the first place), some kind of "backward compatible behavior" must be enabled. But why, and how?
(The docbook stylesheet in question does specify <xsl:stylesheet version="1.0" xmlns:saxon="http://icl.com/saxon">.)
I'm no expert in DocBook, but I believe the Docbook 1.0 stylesheets probably work best with Saxon 6.5.5, and if you want to use the latest Saxon releases (e.g. for performance) then you're probably better off using the Docbook 2.0 stylesheets: see
http://norman.walsh.name/2011/08/25/docbook-xslt-2
If you want to run XSLT 1.0 stylesheets trying to access extensions in the namespace xmlns:saxon="http://icl.com/saxon" then you should use the lastest version of Saxon 6 which is 6.5.5 I think.
Saxon 9 is an XSLT 2.0 processor and I don't think that comment talking about "Saxon 6.4.2 or later" has Saxon 9 in mind, it is solely talking about the Saxon 6.x releases of the XSLT 1.0 processor.
Other than that I agree with Ken, if you want to use Saxon 9 then edit the stylesheets to use the XSLT 2.0 xsl:result-document.
Saxon 9 supports XSLT 2.0, so just use <xsl:result-document> to create multiple result trees.
I have multiple XSLT files that I'm using to process my source XML in a pipeline. I know about the trick with exsl:node-set but after having some issues with this workflow, I took the decision to split the various passes into separate XSL files. I'm much happier with the structure of the files now and the workflow works fine in Eclipse. Our release system works with ant. I can process the files like this:
<xslt basedir="src-xml" style="src-xml/preprocess_1.xsl" in="src-xml/original.xml" out="src-xml/temp_1.xml" />
<xslt basedir="src-xml" style="src-xml/preprocess_2.xsl" in="src-xml/temp_1.xml" out="src-xml/temp_2.xml" />
<xslt basedir="src-xml" style="src-xml/preprocess_3.xsl" in="src-xml/temp_2.xml" out="src-xml/temp_3.xml" />
<xslt basedir="src-xml" style="src-xml/finaloutput.xsl" in="src-xml/temp_3.xml" out="${finaloutput}" />
But this method, going via multiple files on disk, seems inefficient. Is there a better way of doing this with ant?
Update following Dimitre's suggestion
I've created myself a wrapper around the various other XSLs, as follows:
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:fn='http://www.w3.org/2005/xpath-functions' xmlns:exslt="http://exslt.org/common">
<xsl:import href="preprocess_1.xsl"/>
<xsl:import href="preprocess_2.xsl"/>
<xsl:import href="preprocess_3.xsl"/>
<xsl:import href="finaloutput.xsl"/>
<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-imports />
</xsl:template>
</xsl:stylesheet>
This has... not worked well. It looks like the document had not been preprocessed before the final output XSL ran. I should perhaps have been clearer here: the preprocess XSL files are modifying the document, adding attributes and the like. preprocess_3 is based on the output of ..._2 is based on ..._1. Is this import solution still appropriate? If so, what am I missing?
The more efficient method is to perform a single, multipass transformation.
The files can remain as they are -- they will be imported using xsl:import instructions.
The savings are obvious:
Just one initiation (loading of the XSLT processor).
Just one termination.
Eliminates the two intermediate files and their creation, writing into, closing and deleting.
Hmm, you say I know about the trick with exsl:node-set, but you don't use it in your attempt ("Update following Dimitre's suggestion"). In case you don't know it, or for the others (like me) who don't know how to perform multipass transformation, here is a nice article: Multipass processing.
The drawback of this approach is that it requires engine specific xsl code. So if you know the engine, you could try this. If you don't know the engine, you could try with solutions from result tree fragment to node-set: generic approach for all xsl engines.
Looking at these sources one conclusion is sure: your current solution is more readable. But you are seeking efficiency, so some readability may be sacrificed.
This is my XML document:
<?xml version="1.0"?>
<?xml-stylesheet type='text/xml' href='/foo.xsl'?>
<document/>
This is /foo.xsl:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:foo="foo"
version="2.0" exclude-result-prefixes="xs">
<xsl:function name="foo:const" as="xs:string">
<xsl:text>ABC</xsl:text>
</xsl:function>
<xsl:template match="/">
<xsl:value-of select="foo:const()"/>
</xsl:template>
</xsl:stylesheet>
Works fine with Saxon 8.7 and produces ABC, as an output. But in Safari and in Chrome this document doesn't work (just an empty page with no error messages). What is it about? Safari and Chrome don't support XSL functions?
Sadly, none of the browsers yet support XSLT 2.0 natively. I think they're all waiting for the others to move first.
Have you tried using SaxonCE?
This is Saxon 9.x implemented in Javascript -- it is reported to work with any of the five major browsers.
At the last Balisage conference Michael Kay (#Michael Kay ) demoed this working on his iPhone.
I am trying to modify an xsl which is of the older version. I come across the following:
<xsl:eval>FormatAccount(this)</xsl:eval>
<xsl:script>
function FormatAccount(e) {
// function details
}
</xsl:script>
I am trying to call the FormatAccount() javascript function using <xsl:eval> and the function is written in <xsl:script>.
How to do this as per the latest standards?
The latest standard is XSLT 2.0 http://www.w3.org/TR/xslt20/, it does not have any facility to define functions in Javascript, it however allows you to define functions with XSLT itself: http://www.w3.org/TR/xslt20/#stylesheet-functions.
XSLT 2.0 is supported by XSLT 2.0 processors like Saxon 9 http://saxon.sourceforge.net/, AltovaXML Tools http://www.altova.com/altovaxml.html or XQSharp http://www.xqsharp.com/xqsharp/beta.htm.
If you want to use Javascript to define extension functions we need to know which XSLT processor you use, of those three XSLT 2.0 processors I mentioned I think only AltovaXML Tools allows that (http://manual.altova.com/AltovaXML/altovaxmlcommunity/index.html?xextmsxsl.htm), and only, I think, to allow easier migration of XSLT 1.0 stylesheets written for Microsoft MSXML.
If you want to use an XSLT 1.0 processor then there too defining extension functions in a particular programming language like Javascript depends on the processor you use, for MSXML there is an msxsl:script element: http://msdn.microsoft.com/en-us/library/ms256042.aspx.
Embedded extension functions in other language is not the content model of XSLT.
Extension elements and extension functions are part of the content model as described in http://www.w3.org/TR/xslt#extension : it's implementation dependant how exactly an XSLT processor register those extensions.
As pointed by #Martin Honnen's answer, in XSLT 2.0 you can declare "stylesheet functions" with XSLT itself.