(Inspired by an old question)
I have some stylesheets that use the anonymous document('') function to implement look-up tables.
<!-- example the lookup table data -->
<ref:data xmlns:ref="urn:inline-data">
<phrasebook>
<!-- English -->
<lang code="en">
<phrase code="USD_PREFIX">$ </phrase>
<phrase code="GBP_PREFIX">£</phrase>
<phrase code="EUR_PREFIX">€</phrase>
<phrase code="JPY_PREFIX">¥</phrase>
</lang>
...
</phrasebook>
</ref:data>
<!-- the lookup table variable I can use elsewhere -->
<xsl:variable name="phrasebook" select="document('')/xsl:stylesheet/ref:data/phrasebook" xmlns:ref="urn:inline-data"/>
(the ref namespace is actually in the stylesheet definition, but included here for brevity)
The problem is that running such a stylesheet with a String StreamSource
fails, but a File StreamSource
works.
From this comment, I understand that it's because the SystemId
is not set on the StreamSource
for the Transformer
to obtain. But to what should I set the SystemId
for a String in memory, rather than a File
?
You'll need to implement a custom URIResolver
Source xmlSource = ...
String xslt = "<xsl:stylesheet>...</xsl:stylesheet>";
// use a supplier here to avoid duplication but ensure we get a new Reader each time
Supplier<Source> xsltSourceSupplier = () -> {
Source xsltSource = new InputSource(new StringReader(xslt));
xsltSource.setSystemId("foo.xslt"); // always be sure to set systemId!
return xsltSource;
};
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsltSourceSupplier.get());
transformer.setURIResolver(new URIResolver() {
public Source resolve(String href, String base) {
System.out.println(String.format("resolve: href=%s, base=%s", href, base));
if ("".equals(href)) {
return xsltSourceSupplier.get();
}
throw new RuntimeException("TODO: Add support for resolving " + href);
}
});
StreamResult result = new StreamResult("output.html");
transformer.transform(xmlSource, result);