Read XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition Online
Authors: Michael Kay
Technically, this interface is rather poorly named. The Internet RFCs distinguish the process of
resolving
a relative URI against a base URI, which is essentially a syntactic operation on two character strings, from the process of
dereferencing
the resulting absolute URI, which typically sends a request over the wires to retrieve some resource. Although the
URIResolver
is passed the relative URI and base URI as separate arguments, it would be bad practice to resolve the relative URI in a nonstandard way. The real power of the
URIResolver
is its ability to control how the absolute URI is dereferenced.
The interface defines only one method:
Method | Description |
Source resolve(String, String) | The first argument is a relative URI, the second is the base URI against which it is resolved. The method returns a Source containing the requested document, or throws a TransformerException if it cannot retrieve it. It may also return null, indicating that the default URIResolver should be used. |
There is a practical problem that the JAXP interface does not address, namely the XSLT rule that if you call the
document()
function twice to fetch the same absolute URI, the same document should be returned each time. Since the
URIResolver
accepts the relative URI and base URI as separate arguments, but does not actually return an absolute URI, it's not entirely clear whether it is the responsibility of the processor or the
URIResolver
to enforce this rule, especially when the URI is in a format that the XSLT processor itself does not recognize, as in the example above.
Note also that the arguments are supplied in the opposite order to those of the Java
java.net.URI
class.
Examples of JAXP Transformations
This section provides some simple examples of applications that use the JAXP API in different ways to control a transformation.
Example 1: Transformation Using Files
This example (
FileTransform.java
) performs a single transformation, reading the source document and stylesheet from files, and sending the XML output to another file.
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.File;
public class FileTransform {
public static void main(String[] args) throws Exception {
StreamSource source = new StreamSource(new File(args[0]));
StreamSource style = new StreamSource(new File(args[1]));
StreamResult out = new StreamResult(new File(args[2]));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer t = factory.newTransformer(style);
t.transform(source, out);
}
}
This is a minimal JAXP application.
At one time I was reluctant to supply
File
objects to the JAXP
StreamSource
and
StreamResult
constructors, because the filename-to-URI conversion was buggy. In recent releases the problems seem to have been fixed.
Assuming you have installed the Sun Java JDK, you can compile this application by the command:
javac FileTransform.java
This assumes that the directory containing the Java source file is the current directory. Once you have compiled the code, you can run it from the command line, for example:
java FileTransform source.xml style.xsl out.html
Of course, this is not a very professionally written application. It will fall over with a stack trace if incorrect arguments are supplied, if either of the input files doesn't exist, or if errors occur during the transformation; but it's a start. My aim in these examples is to show how the main JAXP classes work, not to teach you professional Java programming.
Because some people like to type examples exactly as they are written in the book, the folder containing the Java applications also contains specimen XML and XSL files called
source.xml
and
style.xsl
. So if you make this folder your current directory, you should be able to type the command line above exactly as shown. But, of course, the Java application will handle any source file and any stylesheet. The stylesheet
style.xsl
uses the construct shown at the start of this chapter to place in the output file a comment identifying which XSLT processor was used. So by experimenting with different classpath settings you should be able to satisfy yourself that this code works with multiple XSLT processors.
Example 2: Supplying Parameters and Output Properties
This example,
Parameters.java
, enhances the previous example:
The
main()
method of the enhanced application looks like this:
public static void main(String[] args) throws Exception {
StreamSource source = new StreamSource(new File(args[0]));
StreamSource style = new StreamSource(new File(args[1]));
String title = args[2];
TransformerFactory factory = TransformerFactory.newInstance();
Transformer t = factory.newTransformer(style);
t.setParameter(“title”, title);
t.setOutputProperty(OutputKeys.INDENT, “no”);
t.transform(source, new StreamResult(System.out));
}
This version of the program can be run using a command such as the following. The third argument on the command line (written in quotes because it contains spaces) is now a parameter value for the stylesheet, instead of the output filename.
java Parameters source.xml style.xsl “New organization structure”
Comparing the output with that of the previous example, note that the HTML is no longer indented, and that the contents of the
elements have changed. And, of course, the output is written to the console this time.
Example 3: Holding Documents in Memory
In this example we will hold both the stylesheet and the source document in memory so that they can be used repeatedly. In principle, this would allow us to run different source documents past the same stylesheet, or to use different stylesheets to transform the same source document, but in practice, to keep the example simple, we'll use the same source document and stylesheet repeatedly, changing only the parameters to the transformation. We'll do one transformation using each of the parameters supplied on the command line.
To keep the source document in memory, create a DOM. One way of doing this would be to use the
DocumentBuilder
class defined in the first section of this appendix. But I'd prefer to stick to using the
javax.xml.transform
interfaces in these examples, so I'll do it in a different way. JAXP makes it very easy to do an identity transform, and to build the DOM—all you need is an identity transform that takes the serial file as input and produces the DOM as output.
You could also keep the stylesheet in memory as a DOM, but this would mean validating and compiling it each time it is used. It's better to keep the compiled stylesheet, that is, the
Templates
object.
The main program of this example (
Repeat.java
) looks like this:
public static void main(String[] args) throws Exception {
StreamSource source = new StreamSource(new File(args[0]));
StreamSource style = new StreamSource(new File(args[1]));
TransformerFactory factory = TransformerFactory.newInstance();
// Build a DOM using an identity transform
Transformer builder = factory.newTransformer();
DOMResult result = new DOMResult();
builder.transform(source, result);
Document doc = (Document)result.getNode();
// Compile the stylesheet
Templates templates = factory.newTemplates(style);
// do one transformation for each parameter supplied
for (int i=2; i
Transformer t = templates.newTransformer();
System.out.println(“======= TITLE = ” + args[i] + “=======“);
t.setParameter(“title”, args[i]);
t.transform(new StreamSource(source), new StreamResult(System.out));
}
}
You can run this application from the command line with a command such as:
java Repeat source.xml style.xsl one two three four
This will run the transformation four times, producing output HTML with the title set to
one
,
two
,
three
, and
four
in turn.