When loading artifacts in a Java™ 2
Platform, Enterprise Edition (J2EE) context, you should consider the
special implications that apply when loading resources from local
deployment artifacts.
About this task
Loading local resources—through Class.getResource and
Class.getResourceAsStream—from J2EE deployment artifacts such as EARs,
WARs, and library JAR files can introduce issues when loading related
XML artifacts. Loading an initial local resource using these mechanisms
will succeed, but artifacts loaded from the initial resource typically
will fail to load without specific consideration.
Here is an
example of loading documents at execution time from a stylesheet using
the XPath fn:doc function. In this case, the default behavior is to
resolve documents based on the base URI from the static context.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="names" select="doc('names.xml')"/>
<xsl:template name="loadnames">
<xsl:copy-of select="$names"/>
</xsl:template>
</xsl:stylesheet>
If this is loaded with the
following Java code in a J2EE
environment:
// create the factory
XFactory factory = XFactory.newInstance();
// load the XSLT file from a local resource within a J2EE deployment artifact
StreamSource source = new StreamSource(XSLTDocFunction.class.getResourceAsStream("/samplexslts/doc.xsl"));
// Create an XSL transform executable
XSLTExecutable xslTransform = factory.prepareXSLT(source);
// Create the result
Result result = new StreamResult(new ByteArrayOutputStream());
// Create a dynamic context specifying the XSLT initial template
XDynamicContext dc = factory.newDynamicContext();
dc.setXSLTInitialTemplate(new QName("loadnames"));
// Execute the transformation
xslTransform.execute(dc, result);
you will receive the
following error:
IXJXE0364W: FATAL ERROR: IXJXE0774E: [ERR 0693][ERR FODC0005]
The URI string 'names.xml' does not map to an available document.
The
reason for this error is that in loading the initial XML artifact
(doc.xsl), no static content was established for the base URI. In
this case, the processor will fall back to looking in the current
working directory, which is meaningless in a J2EE environment.
There
are three possible ways to fix this situation. Here are the first
two:
- Set the baseURI in the static context.
Adjusting to set the
baseURI on the static context would look like this example:
// create the factory
XFactory factory = XFactory.newInstance();
// set the baseURI in the static context
URL dataURL = XSLTSchemaAware.class.getResource("/samplexslts/doc.xsl");
XStaticContext staticContext = factory.newStaticContext();
staticContext.setBaseURI(dataURL.toString());
// load the XSLT file from a local resource within a J2EE deployment artifact
StreamSource source = new StreamSource(XSLTDocFunction.class.getResourceAsStream("/samplexslts/doc.xsl"));
// Create an XSL transform executable
XSLTExecutable xslTransform = factory.prepareXSLT(source, staticContext);
// Create the result
Result result = new StreamResult(new ByteArrayOutputStream());
// Create a dynamic context specifying the XSLT initial template
XDynamicContext dc = factory.newDynamicContext();
dc.setXSLTInitialTemplate(new QName("loadnames"));
// Execute the transformation
xslTransform.execute(dc, result);
- Load the resource in a way that allows the processor to know the
baseURI.
Adjusting to load the resource in a way that allows the
processor to know the baseURI by passing the absolute URL to the StreamSource
constructor would look like the following example:
// Create the factory
XFactory factory = XFactory.newInstance();
// Create the source from a URL
URL dataURL = XSLTSchemaAware.class.getResource("/samplexslts/doc.xsl");
StreamSource source = new StreamSource(dataURL.toString());
// Create an XSL transform executable for the expression
XSLTExecutable xslTransform = factory.prepareXSLT(source);
// Create the result
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Result result = new StreamResult(baos);
// Create a dynamic context specifying the XSLT initial template
XDynamicContext dc = factory.newDynamicContext();
dc.setXSLTInitialTemplate(new QName("loadnames"));
// Execute the transformation
xslTransform.execute(dc, result);
These two approaches described will work well when all XML artifacts
are in a single J2EE deployment unit, but they will fail if XML artifacts
are split across J2EE deployment units because there is no single
baseURI for all of the XML artifacts.
To have complete control
over XML artifact loading to support cases such as artifacts spread
across multiple deployment units, use resolvers to completely control
loading behavior.
Implement the appropriate resolvers and register those
resolvers into the static or dynamic context as appropriate. These
XML artifact loading recommendations apply within a J2EE context for
all XML artifacts supported by resolvers such as XML documents (fn:doc(),
document()), stylesheets (xsl:include, xsl:import), unparsed text,
and XML schemas (XSLT import-schema).