XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (690 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
5.54Mb size Format: txt, pdf, ePub

When you call methods defined in the DOM, the result will follow the DOM rules, not the XPath rules. For example, in XPath the string value of an element node is the concatenation of all the text content within that element; but in the DOM, the apparently similar
nodeValue()
method returns
null
.

It's not a good idea to attempt to update a DOM that is passed to an extension function. Three things might happen, depending on the implementation:

  • The attempt to update the DOM may cause an exception.
  • If the DOM was constructed as a copy of the XPath tree, the updates may succeed, but have no effect on the tree as seen subsequently within the stylesheet.
  • If the DOM and the XPath tree are different views of the same data, then updates may affect the subsequent XSLT processing. This might cause subsequent failures, for example, if nodes have been deleted while the XSLT processor holds references to them.

Constructing a new tree, in the form of a DOM, and returning this to the stylesheet as the result of the extension function, is perfectly OK if the implementation allows it.

These rules for the mapping of XPath trees probably seem rather complicated, and there are certainly lots of potential pitfalls. My own advice would be to steer clear of this area if you possibly can. Navigating around the tree is something you can do perfectly well within XSLT and XPath; you don't need to escape into a different language for this. It's simpler, and usually quite adequate, to pass simple strings and numbers to your extension functions.

If you want to write an extension function that constructs and returns a new tree, you might well find that a simpler alternative is to call the
document()
function and implement a
URIResolver
(or in .NET, an
XmlResolver
) that takes the URI provided in this call, and returns the relevant data source. The JAXP URIResolver interface is described in Appendix E, and an overview of the .NET transformation API is provided in Appendix D.

Calling External Functions within a Loop

I wanted to show an example that includes a reasonably realistic stylesheet with multiple calls on extension functions. It turns out that all the examples I used for this in XSLT 1.0 are things that can be done quite straightforwardly with standard facilities in XSLT 2.0. However, with this caveat, I've decided to retain this example to show the principles.

This example is specific to the Saxon processor. It can be made to work with any processor that supports Java extension functions, but it will need minor alterations.

Example: Calling External Functions within a Loop

In this example, we will use a Java
BufferedReader
object to read an external file, copying it to the output one line at a time, each line being followed by an empty


element. (The alternative way of doing this would be to read the file using the
unparsed-text()
function described in Chapter 13, and then to break it into its lines using

.)

Source

This stylesheet doesn't need a primary source document.

The real input is a serial file, which can be any text file. For example, the following
hiawatha.txt
:

Take your bow, O Hiawatha,

Take your arrows, jasper-headed,

Take your war-club, Puggawaugun,

And your mittens, Minjekahwan,

And your birch-canoe for sailing,

And the oil of Mishe-Nama.

Stylesheet

The stylesheet can be downloaded as
reader.xsl
.

First, we declare the namespaces we will need. It's often easiest to declare these namespaces on the

element itself. I shall stick to the convention of using the
java:*
URI to identify the name of the Java class, and I will also use the abbreviated class name as the namespace prefix. You won't usually want these namespaces appearing in the result document, so you can suppress them using
exclude-result-prefixes
.

    xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”

    version=“2.0”

    xmlns:xs=“http://www.w3.org/2001/XMLSchema”

    xmlns:FileReader=“java:java.io.FileReader”

    xmlns:BufferedReader=“java:java.io.BufferedReader”

    exclude-result-prefixes=“FileReader BufferedReader”>

The name of the file we want to read from will be supplied as a parameter to the stylesheet. We need to declare the type of the parameter, because the Java class has three constructors that take a single argument, and Saxon needs to know (at compile time) which of them to call.


When we are ready to read the file, we create the
BufferedReader
in a variable. Then we call a template to read the file, line by line.



    

              select=“BufferedReader:new(FileReader:new($filename))”/>

    

        

    



The
read-lines
template reads and outputs the first line of the file, and then calls itself recursively to process the remainder. The
readLine()
method of the
BufferedReader
class returns
null
to indicate that the end of file has been reached, and in Saxon, a Java null is translated to a return value of an empty sequence. So we test whether to continue the recursion using the test
exists($line)
, which returns
false
when the return value was null.


    

    

                  select=“BufferedReader:readLine($reader)”/>

    

        

        

            

        

    



Note that this template is tail-recursive: it does no further work after calling itself. This means that a processor that provides tail-call optimization should be able to handle arbitrary long input files. A processor without this feature may fail with a stack overflow, perhaps after reading 500 or 1000 lines of text.

Output

When you run this stylesheet, you need to supply a value for the filename parameter. For example:

java net.sf.saxon.Transform -it:main -xsl:reader.xsl filename=hiawatha.txt

This command line invokes Saxon without a source document, specifying
main
as the name of the first template to be executed, and
hiawatha.txt
as the value of the
filename
parameter.

Other books

Joe Pitt 5 - My Dead Body by Huston, Charlie
Looking For Trouble by Becky McGraw
Rumpole Misbehaves by John Mortimer
Moving Parts by Magdalena Tulli
Outing of the Heart by Lisa Ann Harper
The Man in 3B by Weber, Carl
Her: A Memoir by Christa Parravani
New Boy by Julian Houston
That Certain Summer by Irene Hannon