I am using the saxonb9-1-0-8j processor.
I am running my transformation using the <xslt> task in Ant.
I would like to use Saxon's extension functions such as saxon:line-number().
I have found that the -I option allows line numbering for the current document (reference).
My question is: How to allow line numbering via the <xslt> task?
The Ant documentation for <xslt> says there should be a nested attribute element to pass processor specific settings. However, I wasn't able to find the correct syntax.
How can I use Saxon extension functions like saxon:line-number() with Ant?
Try
<factory name="net.sf.saxon.TransformerFactoryImpl">
<attribute name="http://saxon.sf.net/feature/linenumbering" value="true"/>
</factory>
The suggestion is based on the 9.5 documentation http://saxonica.com/documentation9.5/using-xsl/xsltfromant.html, I would guess it is not different in 9.1, check its documentation yourself at http://saxon.sourceforge.net/ if needed.
Related
What is the recommended way in Saxon to load in an XML document from eXist-db via XQuery GET/POST within an XSL stylesheet? I want to run an XQL query in eXist-db, which should be simple enough to do as a GET with <xsl:variable name="test" select="doc('xmldb:exist:///db/test.xql')"/> or <xsl:variable name="test" select="doc('http://localhost:8080/exist/rest/db/test.xql')"/>. But the former doesn't exectute the query and tries to return the XQL source as XML, and the latter doesn't have the basic authentication to execute. Also, I really want to send an XML fragment using POST, and have the XQL use that posted XML fragment.
I can't find anything in the Saxon documentation about this. I did find an old EXPath article at http://expath.org/modules/http-client/samples, but the downloads there are 7 years old, and may not work with modern Saxon. So looking for the best known method to do this.
The first thing that comes to mind is the EXPath HTTP Client module. There's no way to persuade the doc() or document() functions to do POST instead of GET, AFAIK.
with IE at its EOL and allowing file access from files in Chrome is not a viable option for us, what is the future of XSLT reports?
I am fairly new to this, and have just been "thrown" into finding a solution. Everything I'm finding online is years old, it's strange that no one is talking about this since "death" of IE.
our data is in XML format, using XSL templates to display formatted reports to browser via ScriptX (smsx.cab) (with page breaks, headers, etc). The user then "prints to PDF"
I am hoping to see what other organizations are doing to ensure existing XSLT reports continue to work. Converting to something else? Making them work with other, currently supported, browsers?
thank you, all and any tips, links and comments much appreciated.
You could try executing your XSLT transformations using a local script.
Take note that these solutions only support XSLT 1.0.
MSXML
successor of msxsl.exe?
PowerShell
Applying XSL to XML with PowerShell : Exception calling "Transform"
If you want to use XSLT 2.0+
You can use Saxon and call the jar file from a batch file.
https://www.saxonica.com/
I'm trying to generate an XML file with the my machine's hostname in some arbitrary element or attribute, e.g.
<hostname>myHostname</hostname>
I'm using Saxon 9.2. I can think of three ways to do this:
Read and parse /etc/sysconfig/network (I'm using Fedora)
Read the environment variable (as in $ echo $HOSTNAME)
Pass the hostname to saxon and then use somehow dereference a variable (not sure if this is possible)
Are any of these possible? I think the first option is most likely to work, but I think the other two options will produce less verbose XSLT.
I also have a related question:
Currently, I have an XSLT and source XML file that generates a bunch of XML files, it works like I expect it to. Is there anyway I can selectively generate one file per host? That is, I want to say 'if the hostname is myHostName then generate the XML file for myHostName, if the hostname is myOtherHostName then generate the XML file for myOtherHostName'.
I ask this because I'm trying to configure a large number of machines and if I could drop an XSLT and XML file on each and then call the same command on every machine and hten get the right XML on each it would be really convienent.
You should pass a parameter to your xslt when "calling" it. I think this is the most robust solution.
So at the top of your stylesheet you would have something like :
<xsl:param name="hostName"/>
Then you can use it in your .xslt via the usual notation : $hostName etc.
You just then need to pass those parameters when calling the xslt processor. Depending on how you use it this may vary.
You can generate an XML file containing all needed parameters, then you can either pass it as parameter to the transformation (refer to the code samples to see examples of how this is done with Saxon).
Here is a link that can help: https://www.saxonica.com/html/documentation/javadoc/net/sf/saxon/expr/instruct/GlobalParameterSet.html
Or simpler, save this XML file in the file system and just pass as parameter to the transformation the file path and name.
Then inside the transformation, use the standard XSLT function document() to load the XML document that contains the parameters.
Even further simplification is possible, if this file can be stored at a location that has exactly the same path on all machines. Then this avoids the need to pass this filepath as parameter to the transformation.
There are many possible ways of doing this: passing in parameters, reading the configuration file using the unparsed-text() function, calling an extension function.
But perhaps the most direct way is that Saxon 9.3 implements the new XPath 3.0 function get-environment-variable(). Support for XPath 3.0 requires Saxon-PE or higher.
(XPath 3.0 is of course still a draft and subject to change. In fact it has changed since Saxon 9.3 was released - the function has been renamed environment-variable()).
I am trying to execute the string contained in an XSL variable.
Umbraco has hooks for several Exslt pieces, but it seems the Exslt.dyn (Exslt.dynamic) is not one of them.
How do you add it in? Acceptable methods (in order of preference:
Writing your own XSLT extension (possibly using existing Umbraco code for Exslt Dynamic).
Uploading the XSL from http://www.exslt.org/dyn/functions/evaluate/index.html into Umbraco.
Modifying the Umbraco source to add it (possibly using existing Umbraco code for Exslt Dynamic).
The reason I mention Exslt Dyanmic is because some Umbraco XSLT sources show a reference that I am assuming existing in some versions of Umbraco. I cannot find it in the source code, however. (Example: the XSL sources pasted in here: http://our.umbraco.org/projects/starter-kits/business-website-starter-pack/general-%28bugs,-feedback,-feature-requests%29/8085-Changing-the-first-day-to-fx-monday)
Very few XSLT processors implement dyn:evaluate() and Umbraco obviously doesn't use one of these.
There isn't anything you can do in this case.
Ask the Umbraco developers to incorporate an XSLT 2.0 processor in the future -- XSLT 2.0 has a native <xsl:function> instruction for defining functions that can be referenced in any XPath expression.
Not sure if this will work, but if Exslt.ExsltDynamic is supported out of the box in the .Net implementation of XSLT, this should work. In your stylesheet add the namespace xmlns:Exslt.ExsltDynamic="urn:Exslt.ExsltDynamic" (as in the example you linked) and in the exclude-result-prefixes property add Exslt.ExsltDynamic to make it accessible in your xslt file.
Then you can just do something like in your template.
I'm trying to run an XSLT transformation from an ant file.
I'm using a XSLT 2.0 stylesheet with a saxon 9 parser (supporting XSLT 2.0).
The problem is that it seems that ant is always calling an XSLT 1.0 parser.
Here's my ant file :
<xslt style="stylesheet.xslt"
basedir="core/"
extension=".xml"
destdir="core/"
classpath="D:\\DevTools\\saxon\\bin\\saxon9.jar">
</xslt>
If I call it directly (without ant), it's working.
Any idea ?
The problem is that while Saxon is added to the classpath, the default JAXP mechanism to determine which TransformerFactory is used and it will use the default that is Xalan. You either need to:
Set javax.xml.transform.TransformerFactory system variable to net.sf.saxon.TransformerFactoryImpl,
Add saxon9.jar to the CLASSPATH system variable, or
Use <factory name="net.sf.saxon.TransformerFactoryImpl"/> inside the xslt element
If you are having this problem, check that you are not using Ant 1.8.1, because there is a bug in Ant 1.8.1 that prevents this from working. (Though this is not the problem in the original post, because that was before Ant 1.8.1 was released).
Your options are:
Use a version of Ant that does not have the bug (e.g. Ant 1.7.1).
Explicitly specify saxon9.jar in the CLASSPATH to Ant before it starts, by either:
Setting the system CLASSPATH environment variable, or
Use the -lib command line option to ant
Define your own task using SAXON Ant (as described by another answer on this thread).
Workaround by adding processor="org.apache.tools.ant.taskdefs.optional.TraXLiaison" as an attribute of the xslt task element.
I would suggestion using option 1, followed by option 4.
Option 2 will work, but it places the responsibility on the person running ant to set up their environment and run ant properly. I assume you don't want that, which is why you are trying to get the classpath attribute on the xslt task to work.
Option 3 has limitations, because SAXON Ant requires downloading and installing its JAR file. Also SAXON Ant does not work with SAXON 9.2 or later (and SAXON Ant has not been updated since it was created in June 2008).
In theory, specifying a factory subelement makes the XSLT processor that you want to use explicit -- to prevent the class loader from finding a different XSLT processor earlier in its search, and using it instead of your XSLT processor which is further down in the CLASSPATH. In practice (at least in ant 1.7.0, 1.7.1 and 1.8.0) if the factory subelement is specified the xslt task ignores the classpath attribute -- which means you have to resort to explicitly specifying the CLASSPATH (option 2). So it doesn't help solve the original problem. However, this seems to have been fixed in the Ant source code, so could work in releases after 1.8.1.
This tutorial seems to give step by step instructions on how to do what you are asking:
http://www.abbeyworkshop.com/howto/xslt/ant-saxon/index.html
From that it appears you are doing the correct thing. Are you sure you need the double back slashes?
Update: The xslt Ant documentation mentions the 'factory' property which may help you get closer:
http://ant.apache.org/manual/Tasks/style.html
EDIT: Dr. Michael Kay has pointed out that the AntTransform is no longer supported, nor recommended.
Create a taskdef from the Saxon AntTransform class:
<taskdef name="saxon-xslt" classname="net.sf.saxon.ant.AntTransform" classpath="${basedir}/lib/saxon/saxon9.jar;${basedir}/lib/saxon/saxon9-ant.jar"/>
<saxon-xslt
in="${source.xml}"
out="${out.dir}/${output.xml}"
style="${basedir}/${stylesheet.xsl}"
force="true">
</saxon-xslt>
I have begun using the standard <xslt> task with the saxon jar specified in a <classpath>, but had been running into performance issues. It seemed to "hang" for a bit when the task was called. I have found that adding processor="trax" and specifying <factory name="net.sf.saxon.TransformerFactoryImpl"/> helps it run much faster.
<xslt in="${source.xml}"
out="${out.dir}/${output.xml}"
style="${basedir}/${stylesheet.xsl}"
processor="trax">
<factory name="net.sf.saxon.TransformerFactoryImpl"/>
<classpath refid="saxon-classpath" />
</xslt>
Rather than waiting for this to be fixed in 1.8.2 and then waiting for everyone to eventually upgrade to 1.8.2, you can roll your own XSLT macro (for situations where you explicitly want to use Saxon, rather than a user selected XSLT engine)
<macrodef name="xslt" uri="com.mycompany.mydepartment">
<attribute name="in" />
<attribute name="out" />
<attribute name="style" />
<attribute name="classpath" default="${saxon.jar.path}" />
<attribute name="taskname" default="mydep:xslt" />
<element name="params" optional="true" implicit="true" />
<sequential>
<java classname="net.sf.saxon.Transform"
classpath="#{classpath}"
taskname="#{taskname}">
<classpath path="${saxon.jar.path}" />
<arg value="-s:#{in}" />
<arg value="-xsl:#{style}" />
<arg value="-o:#{out}" />
<params />
</java>
</sequential>
</macrodef>
you can then invoke it like (assuming xmlns:mydep="com.mycompany.mydepartment" is set on the project element)
<mydep:xslt in="${myinput}"
out="${myoutput}"
style="${myxslt}">
<arg value="param1=value1" />
<arg value="param2=value2" />
<arg value="+param3=somefile.xml" />
</mydep:xslt>
You can find the docs for passing parameters to Saxon at http://www.saxonica.com/documentation/using-xsl/commandline.xml
At least in ant 1.8.0, the xslt task with a specified classpath is very slow.
The problem seems to be classpath loading. I ran ant under JDB and it spent all of the extra time in org.apache.tools.ant.AntClassLoader.loadClass reading zip files.
I tried this before running ant it it went a lot faster:
ant -lib /path/to/saxon/saxon9.jar
The macrodef from Tom Howard works better, and although it has an odd syntax for XSLT params, at least it's possible.