tags:

views:

81

answers:

4

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.

+1  A: 

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).

Eamon Nerbonne
+2  A: 

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.

Evan Lenz
`XslCompiledTransform` (.NET 2.0 XSLT implementation) also supports `exsl:node-set()` in the correct namespace, even though they do not document it. They also support `exsl:object-type()`.
Pavel Minaev
+1  A: 

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.

Jukka Matilainen
thanks for the reply, but i was actualy hoping to do the opposite,ie. not having any reference to windows in the docbook itself, but having the xslt generate different outputs bases on the parameter.(the reason is becasue the docbook is written by non technical staff and we would like to keep 'code-like' clutter to a minimum)
pvgoddijn
A: 

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.

Erlock