XSLT template outputting differently under different Saxon installs? (eXist-db) - xslt

In my site I use XQuery 3.1 (under eXist-db 4.4) to output XSLT 2.0 transformations of TEI-XML documents.
Take for example this document http://medieval-inquisition.huma-num.fr/doc/MS609-0176
In my function I get the tei-xml document MS609-0176.xml as $doc and the dynamically prepared XSLT as $stylesheet and then execute the transform:transform
The serialized $stylesheet (with all nodes included for the parameters) and the tei-xml document are pasted here:
https://xsltfiddle.liberty-development.net/bdxtrg/6
One of the principle jobs of this transformation is to output footnotes.
The transformation in XSLT fiddle outputs correctly: there are 3 footnotes.
But on the website, the identical transformation and Saxon processor using the identical documents outputs 5 footnotes.
In fact, the problem (across all transformations) is only with processing tei:date[#type='deposition_date']. The transformation is 'triple-processing' all references to tei:date[#type='deposition_date'] where it only ever exists once in the file. This is happening to this one element in every document (as can be seen by looking at any on the site).
In terms of process steps: footnote numbers are added to the body, then in a separate mode, the XSLT file then uses those numbers to build the footnotes at the bottom. Therefore the problem is in the first step.
The footnote numbers are assigned to tei:date[#type='deposition_date'] at line 80-84 in the XSLT fiddle. They are processed in a unique template from the other elements.
For reference, the Xquery function is:
declare function document:doc-docview($node as node(), $model as map(*), $docset as xs:string)
{
let $stylesheet := document-view:doc-view-xslt($docset)
let $doc := doc(concat($globalvar:URIdata,$docset))
return transform:transform($doc,$stylesheet,())
}
I am completely mystified about how to handle this problem. It's the same processor (Saxon) but different result? Is there some adjustment I can make to the the XSLT file to mitigate this problem?
(I have run the exact same transformation in Oxygen (using Saxon as well), and it produces the correct results as well.)
The eXist-db environment can be accessed and tested here http://ciham-digital.huma-num.fr/exist/apps/eXide/index.html under /db/apps/deheresi/data/MS609-0176.xml and /db/apps/deheresi/modules/document-view (function) document-view:doc-view-xslt

Related

Is it possible to generate both HTML and Wiki markup at the same time using XSLT?

I would like to generate both HTML and Wiki markup at the same time using XSLT (from an XML source document) - just wondering if it's possible. It would be nice if I could use the same XSLT to do both rather than writing/maintaining two separate files.
The HTML report will be for general viewing, and the Wiki markup will be published to Confluence.
If you want to create more than one result document using a single stylesheet than XSLT 2.0 and later support that using xsl:result-document, see the specification http://www.w3.org/TR/xslt20/#creating-result-trees. As you then want to process the same elements twice, you usually also make use of modes to separate the different processing, e.g. use one mode to produce HTML, the other mode to produce Wiki markup.
With pure XSLT 1.0 you can only create a single result document, however, some XSLT 1.0 processors, like Xalan (http://xml.apache.org/xalan-j/extensions_xsltc.html#redirect_ext) or xsltproc (http://exslt.org/exsl/elements/document/index.html) support an extension to create more than one result document.

XSL include based on XSL:WHEN condition

I have a scenario here I have multiple xsl designed for different type of XML files. Now I have some application ID that is passed to my XSL library with now I want to load different xsl based on this application ID values.
Like if my application ID is 1
if application ID is 2
how can I do this???
Please help
In XSLT, xsl:include and xsl:import must be top-level elements, as said in the specifications (here for version 1.0).
That means that you can not condition the loading of another XSL file based on the XML you are applying the XSL to.

How to use an expression in xsl:include element in an XSLT processing

I need to include an XSLT that exists in 2 variants, depending on a param value.
However, it's seems to be not possible to write an expression in the href attribute of the xsl:include element. My last trial looks like that:
< xsl:param name="ml-fmt" select="mono"/>
...
< xsl:include href="{$ml-fmt}/format.xsl"/>
The XSLT engine used is Saxon 9.2.0.6
Have anybody an idea about how I could do something close to that ?
As Dimitre has said you can't do it, but you can generate the XSLT file from scratch or slightly modify an existing XSLT file by inserting the node in the code preparing the transformation.
You can't.
If you know all possible xslt stylesheet modules to be included, you could use the xsl:use-when attribute in order to selectively include only some of them. However, xsl:use-when has its own limitations. To quote the XSLT 2.0 Spec:
"Any element in the XSLT namespace may have a use-when attribute whose value is an XPath expression that can be evaluated statically".
There is a way to achieve dynamic inclusion, but it requires some non-XSLT initialization:
The code (think C# or Java or ... your programming language) that invokes the transformation, can edit the DOM of the loaded (as XML) XSLT stylesheet and can set the value of the href attribute of any <xsl:import> element to the desired URL.

preproccesing in XSLT

is it at all possible to 'pre-proccess' in XSLT?
with preprocessing i mean updating the (in memory representation) of the source tree.
is this possible, or do i need to do multiple transforms for it.
use case:
we have Docbook reference manuals for out clients but for certain clients these need different 'skins' (different images etc). so what i was hoping to do is transform the image fileref path depending on a parameter. then apply the rest of the normal Docbook XSL templates.
Expanding on Eamon's answer...
In the case of either XSLT 1.0 or 2.0, you'd start by putting the intermediate (pre-processed) result in an <xsl:variable> element, declared either globally (top-level) or locally (inside a template).
<xsl:variable name="intermediate-result">
<!-- code to create pre-processed result, e.g.: -->
<xsl:apply-templates mode="pre-process"/>
</xsl:variable>
In XSLT 2.0, the value of the $intermediate-result variable is a node sequence consisting of one document node (was called "root node" in XSLT/XPath 1.0). You can access and use it just as you would any other variable, e.g., select="$intermediate-result/doc"
But in XSLT 1.0, the value of the $intermediate-result variable is not a first-class node-set. Instead, it's something called a "result tree fragment". It behaves like a node-set containing one root node, but you're restricted in how you can use it. You can copy it and get its string-value, but you can't drill down using XPath, as in select="$intermediate-result/doc". To do that, you must first convert it to a first-class node-set using your processor's node-set() extension function. In Saxon 6.5, libxslt, and 4xslt, you can use exsl:node-set() (as in Eamon's answer). In MSXML, you'd need to use msxsl:node-set(), where xmlns:msxsl="urn:schemas-microsoft-com:xslt", and in Xalan, I believe it's called xalan:nodeset() (without the hyphen, but you'll have to Google for the namespace URI). For example: select="exsl:node-set($intermediate-result)/doc"
XSLT 2.0 simply abolished the result tree fragment, making node-set() unnecessary.
This is not possible with standards compliant XSLT 1.0. It is possible in every actual implementation I've used, however. The extensions with which to do that differ by engine, however. It is also possible in standard XSLT 2.0 (which is in any case much easier to work with - so if you can, just use that).
If your xslt processor supports EXSLT, the exsl:node-set() function does what you're looking for. msxml has an identically named extension function as well (but with a different namespace uri, the functions are unfortunately not trivially compatible).
Since you are trying to generate slightly different output from the same DocBook XML source, you might want to look into the "profiling" (conditional markup) support in DocBook XSL stylesheets. See Chapter 26 in DocBook XSL: The Complete Guide by Bob Stayton:
Profiling is the term used in DocBook
to describe conditional text.
Conditional text means you can create
a single XML document with some
elements marked as conditional. When
you process such a document, you can
specify which conditions apply for
that version of output, and the
stylesheet will include or exclude the
marked text to satisfy the conditions.
This feature is useful when you need
to produce more than one version of a
document, and the versions differ in
minor ways.
For example, to use different images for, say, Windows and Mac versions of the same document, you might have a DocBook XML fragment like this:
<figure>
<title>The Foo dialog</title>
<mediaobject>
<imageobject os="windows">
<imagedata fileref="screenshots/windows/foo.png"/>
</imageobject>
<imageobject os="mac">
<imagedata fileref="screenshots/mac/foo.png"/>
</imageobject>
</mediaobject>
</figure>
Then, you would use the profiling-enabled versions of the DocBook XSL stylesheets with the profile.os parameter set to windows or mac.
Maybe you should use XSLT "OOP" methods here. Put all the common templates to all clients in a stylesheet, and create an stylesheet for each client with specific templates overriding common ones. Import the common stylesheet within the specific ones with xsl:import, and you'll do only one processing by calling the stylesheet corresponding to a client.

Is it possible to create "two step view" with XSLT only

I am trying to transform XML file twice with different XSLT files (Two step view). Is it possible to do so?
Example:
data.xml -> transformed by first.xsl -> result of first transformation (XML) -> transformed by second.xsl -> result of second transformation (HTML)
Unfortunately, with standards-compliant XSLT 1.0: no, this is not possible.
In XSLT 2.0, a template's return value may be used as input to another template; so an upgrade to XSLT 2.0 (which is easier to work with on many other fronts as well) would solve this limitation for you.
Another workaround is using the node-set extension function: but, being non-standard, this is obviously not supported everywhere identically: see http://www.xml.com/pub/a/2003/07/16/nodeset.html for details.
In XSLT 2.0 this is supported -- just capture in an <xsl:variable/> the result of the first transformation, then apply templates (possibly with different mode) to the top child (or any other descendents) of the xml document/fragment contained in the xsl:variable.
In XSLT 1.0 one has to use the xxx:node-set() extension, which converts the contents of the xsl:variable (which is of type RTF -- Result Tree Fragment) into a regular XML document/fragment.
This extension-function is quite standardized by EXSLT -- the "most standard" and widely implemented library of XSLT 1.0 extension functions.