XSLT lookup using key when XSLT Source is processed from String in java
I am trying to process an XSLT lookup - taking the input XSLT as a String instead of a file after certain modifications. Everything works well if I write the modified XSLT as a file and read it again for transformation but when I process this as a String, the look-up does not function .
The method doing the transformation is as below.
public static void transform(File inputXmlfile, String outputXmlFileName) throws ParserConfigurationException, SAXException, IOException, TransformerException {
DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = docBuildFactory.newDocumentBuilder();
Document document = parser.parse(inputXmlfile);
TransformerFactory xformFactory = TransformerFactory.newInstance();
String xsltString="<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
"<xsl:stylesheet version=\"1.0\""+
" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:c=\"http://myDomain.com/classifications.data\">"+
"<xsl:output method=\"xml\" />"+
"<xsl:key name=\"classification-lookup\" match=\"c:classification\" use=\"c:id\" /> <xsl:template match=\"/\"><listings xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://local.google.com/local_feed.xsd\"><language>en</language><datum>WGS84</datum>" +
"<xsl:for-each select=\"BusinessListings/BusinessListing\"><listing><id><xsl:value-of select=\"id\" /></id><xsl:apply-templates /></listing></xsl:for-each></listings></xsl:template><xsl:template match=\"classificationId\"><xsl:variable name=\"currentId\" select=\".\" />" +
"<xsl:for-each select=\"document('')\">开发者_如何学JAVA;<category><xsl:value-of select=\"key('classification-lookup',$currentId)/c:description\" /></category></xsl:for-each></xsl:template> <xsl:template match=\"text()\" />" +
"<c:classifications><c:classification><c:id>3</c:id><c:description>Abortion Alternatives</c:description></c:classification><c:classification><c:id>4</c:id><c:description>Abortion Providers</c:description>" +
"</c:classification><c:classification><c:id>9</c:id><c:description>Abrasives</c:description></c:classification></c:classifications></xsl:stylesheet>";
Transformer transformer = xformFactory.newTransformer(new StreamSource(IOUtils.toInputStream(xsltString)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
FileOutputStream fileOutputStream = new FileOutputStream(new File(outputXmlFileName));
DOMSource source = new DOMSource(document);
Result result = new StreamResult(fileOutputStream);
transformer.transform(source, result);
fileOutputStream.close();
}
when I try this as follows (after writing the modifiel xsl and reading it back)
Transformer transformer = xformFactory.newTransformer(new StreamSource(xsltFile));
it works fine - but
Transformer transformer = xformFactory.newTransformer(new StreamSource(IOUtils.toInputStream(xsltString))); does not process the lookup.
The input is as below
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BusinessListings vendorId="0" schemaVersion=""
fileCreateDate="" xmlns="http://www.myDomain.com">
<BusinessListing>
<id>1593469</id>
<listingData>
<classifications>
<classificationId>3</classificationId>
<classificationId>9</classificationId>
</classifications>
</listingData>
</BusinessListing>
</BusinessListings>
what could the issue be ?
First, to answer your question - refer to the XSLT 1.0 spec that explains the use of a zero length string arg to the document function:
Note that a zero-length URI reference is a reference to the document relative to which the URI reference is being resolved; thus document("") refers to the root node of the stylesheet; the tree representation of the stylesheet is exactly the same as if the XML document containing the stylesheet was the initial source document.
Since the source for your stylesheet is an in-memory stream, there is no URI from which to resolve it. It works with a File since it is able to resolve the location of the file and reload it. There may be some way to get this to work with a system-id or custom URI resolver but I think there's likely an easier approach.
Second, why are you embedding the classification data within the XSLT? Why not just pass it in as a param? It seems much easier and will work largely the same by replacing the document('') call with a reference to the param.
Can you pass a ByteArrayInputStream into the StreamSource object? You could initialize that with a String.
Something like:
ByteArrayInputStream bais = new ByteArrayInputStream(xsltString.getBytes(), "UTF-8");
Transformer transformer = xformFactory.newTransformer( new StreamSource( bais ) );
精彩评论