Processing the output of another XSLT Stylesheet - xslt

I have an XSLT stylesheet that produces some output in XML. I want to processes that output with another stylesheet. Is there a way to tell the latter stylesheet to "run and use" the results from the former?

There is not, as far as I know, a standard way to tell an XSLT processor to run another stylesheet on given input and do something with the output. In some cases you can process the input against one set of templates and save the result in a variable, then apply a different set of templates to the value of the variable, something like this:
<xsl:template match="/">
<xsl:variable name="temp">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$temp" mode="second-pass"/>
</xsl:template>
This assumes you're running XSLT 2.0. In XSLT 1.0 you will need a processor that supports the node-set extension (many do), and you'll need to change the reference to $temp to something like exslt:nodeset($temp).
As you will perceive, this won't work very well if your two stylesheets both use the default mode and operate on overlapping sets of element types. So some XSLT processors have added extensions to provide the kind of functionality you describe (see, for example, discussions of the Xalan pipe:pipeDocument extension element).
Of course, you can also handle the pipe outside of XSLT. The simplest way to do it depends upon the environment you are running in.
If you're running XSLT from an operating system shell and your XSLT processor accepts input on stdin, you can pipe the output from one stylesheet into the other:
xsltproc a.xsl in.xml | xsltproc b.xsl - > out.xml
And as mohammed moh has already pointed out, many scripting environments make it possible to do similar things: he mentions PHP, and of course there's XProc.

yes You can. You must Transforms the source node to a DOMDocument I don't Know What is your Programming Language . For Example in php is transformToDoc() after Transforms You Can Run A New XSLT Stylesheet On DOMDocument Output

Related

How to run the <xsl:for-each-group select="*" group-adjacent="boolean(self::table)"></xsl:for-each-group> of xslt2.0 by using xalan

Actually I have two methods :
one is : document-location()
and other is :
<xsl:for-each-group select="*" group-adjacent="boolean(self::table)">
first method is supported to xalan but not saxon and second method is supported saxon but not xalan .
for this I have created two files for two methods . But I dont want to create two different files .Is there any method which works same as in xalan?
The <xsl:for-each-group> construct was introduced in XSLT 2.0, and Xalan only supports XSLT 1.0. If you need to do grouping in XSLT 1.0, you'll have to use the Muenchian grouping method. If there are things in your stylesheet that prevent you migrating from Xalan to Saxon to take advantage of XSLT 2.0 (and 3.0), then please tell us exactly what the issues are and we can probably help you with the migration. (That would be best done in a new question.)
I want ro run document-location() method using saxon.
I cannot find any documentation of what this method actually does.
If - as suggested here - it returns the path to the XML file being processed, you can use the XPath 2.0 base-uri() or document-uri() functions to do the same.

eXist-db / XSLT / Saxon collection() slow as molasses (or errors out with memory limit)

Coming from this question, I managed one entirely unsatisfactory solution for accessing an eXist-DB collection() from an XSLT 2.0 document loaded from within an eXist-db/Xquery transformation function:
The XSLT file declares a variable :
<xsl:variable name="coll" select="collection('xmldb:exist:///db/apps/deheresi/data/collection_ms609.xml')"/>
This points to a catalog xml file I created (per Saxon documentation) that looks like this, in order to load the actual collection:
<collection stable="true">
<doc href="xmldb:exist:///db/apps/deheresi/data/ms609_0001.xml"/>
<doc href="xmldb:exist:///db/apps/deheresi/data/ms609_0002.xml"/>
...
...
<doc href="xmldb:exist:///db/apps/deheresi/data/ms609_0709.xml"/>
<doc href="xmldb:exist:///db/apps/deheresi/data/ms609_0710.xml"/>
</collection>
This allows the XSLT file to use a key that needs to search across all these files:
<xsl:key name="correspkey" match="tei:seg[#type='dep_event' and #corresp]" use="#corresp"/>
<xsl:variable name="correspvar" select="self::seg[#type='dep_event' and #corresp]/#corresp"/>
<xsl:value-of select="$coll/(key('correspid',$correspvar) except $correspvar)/#id" separator=", "/>
As it stands, if I have 50 documents in the catalog, I get a result in 2 minutes; with all 710 I get a java GC error after 4 minutes.
I have set indexes on relevant nodes in eXist-DB, but this does nothing to performance. It seems to me Saxon is working 'outside' eXist-DB's optimisations, treating eXist-DB as a simple file system.
(For what it's worth, setting href="/db/apps/deheresi/data/ms609_0001.xml" does not let Saxon see the documents.)
I suspect all of this is why the eXist-DB documentation is non-existent.
As it goes, I am looking for solutions for intensive searches of collections from within XSLT 2.0 loaded within eXist-DB by Xquery transform().
If anything, I hope this post helps future searchers encountering the same problem.
The general architectural principle is: try to move the searching closer to the data. In this case this means: use eXist to find the documents of interest, don't extract every possible candidate document from eXist and then ask Saxon to do the searching. Select the actual documents of interest in an eXist XQuery, and then pass the list of these documents to Saxon in a stylesheet parameter.

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.

XSLT: How do I trigger a template when there is no input file?

I'm creating a template which produces output based on a single string, passed via parameter, and does not use an input XML document. xsltproc seems to happily run with a single parameter specifying the stylesheet, but I don't see a way to trigger a template without an input file (no parameter to xsltproc to run a named template, for example).
I'd like to be able to run:
xsltproc --stringparam bar baz foo.xsl
But I'm currently having to run, with the "main" template matching "/":
echo '<xml/>' | xsltproc --stringparam bar baz foo.xsl -
How can I get this to work? I'm sure I've seen other templates in the past which were meant to be run without an input document, but I don't remember how they worked or where to find them again. :-)
Actually, this has been done quite often.
In XSLT 2.0 it is defined in the Spec. that providing an initial context node is optional.
If no initial context node is provided (no source XML document), then it is important to provide the name of a named template which is to be executed as the entry point to the transformation.
In XSLT 1.0 one can provide to the transformation its own primary stylesheet module (file) as the source XML document, and of course, the transformation can completely ignore this source XML document. This technique has long ago been demonstrated and used by Jeni Tennison.
For example:
<?xml-stylesheet type="text/xsl" href="example.xml"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<p>Hello, world!</p>
</xsl:template>
</xsl:stylesheet>
When the above code is saved in a file named "example.xml" and then the folder contents is displayed with Windows Explorer, double-clicking on the file "example.xml" will open IE and produce:
Hello, world!
In general, you cannot do this with XSLT - specification requires there to be an input document, and for the processing to start with applying any available templates to its root node. Some XSLT processors might give a way to do what you want (e.g. execute a named template) as an extension, but I don't know any such, and it doesn't seem that xsltproc is one of them, judging from its man page.
In fact, this sounds pretty dubious in general, as the purpose of using XSLT to produce some output from a plain string input is unclear - it's not the kind of task it's generally good at.

Merge multiple xslt stylesheets

I have a xslt stylesheet with multiple xsl:imports and I want to merge them all into the one xslt file.
It is a limitation of the system we are using where it passes around the xsl stylesheet as a string object stored in memory. This is transmitted to remote machine where it performs the transformation. Since it is not being loaded from disk the href links are broken, so we need to remove the xsl:imports from the stylesheet.
Are there any tools out there which can do this?
You can use an XSL stylesheet to merge your stylesheets. However, this is equivalent to using the xsl:include element, not xsl:import (as Azat Razetdinov has already pointed out). You can read up on the difference here.
Therefore you should first replace the xsl:import's with xsl:include's, resolve any conflicts and test whether you still get the correct results. After that, you could use the following stylesheet to merge your existing stylesheets into one. Just apply it to your master stylesheet:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="xsl:include">
<xsl:copy-of select="document(#href)/xsl:stylesheet/*"/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The first template replaces all xsl:include's with the included stylesheets by using the document function, which reads in the file referenced in the href attribute. The second template is the identity transformation.
I've tested it with Xalan and it seems to work fine.
It is impossible to include imported stylsheets into the main file without breaking import precedence. For example, you define a top-level variable in an imported stylesheet and redefine it in the main file. If you merge two files into one, you’ll get two variables with the same name and import precedence, which will result in an error.
The workaround is two replace xsl:import’s with xsl:include’s and resolve any conflicts. After that you are safe to replace xsl:include instructions with the corresponding files’ contents, because that is what XSLT-processor does:
The inclusion works at the XML tree level. The resource located by the href attribute value is parsed as an XML document, and the children of the xsl:stylesheet element in this document replace the xsl:include element in the including document. The fact that template rules or definitions are included does not affect the way they are processed.
A Manual merge is probably going to be the best option.
The main consideration will probably be to make sure that the logic for matching templates works in the combined stylesheet.
Why would you want to? They're usually seperated for a reason afterall (often maintainability)
You could always write the merge yourself - read the XSL files in, select the template items you're interested in and write to a new master XSL file...
import multiple xsl in single xsl
<xsl:import href="FpML_FXOption_Trade_Template1.xsl"/>
<xsl:apply-imports/>
<calypso:keyword>
<calypso:name>DisplayOptionStyle</calypso:name>
<calypso:value>Vanilla</calypso:value>
</calypso:keyword>
<xsl:import href="FpML_FXOption_Trade_Template2.xsl"/>
<xsl:apply-imports/>