Use resolvers in a J2EE context
When loading artifacts in a Java 2 Platform, Enterprise Edition (J2EE) context, we should consider the special implications that apply when loading resources from local deployment artifacts.
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);we 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.
Tasks
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).