Writing XSLT output to the multiple objects in mem

2019-08-23 11:23发布

I'm playing with XSLT and writing the result to the multiple outputs in Java as these links describe: link1, link2.

When it comes to writing to the files everything works perfectly, but now I'd like to store the output XMLs as either Document object or some kind of InputStream/String - anything but file on a drive. Writing the documents to the files using Transformer and than reading them to the objests(Document, String etc.) is not an option.

My question is: what should I change in my xslt map and java code to get the output as an objects, not the files on a drive. (the only solution that I came up with is to use two XSLT on this one XML but it's not the elegant way)

My Java codes are similar to the answers in the links above. I'm using XSLT 2.0 and transform using :

transformer.transform(xmlText, new DOMResult());

I also added

  <xsl:result-document href="{concat($jobName, '_assets.xml')}">
        <xsl:apply-templates select="GetMetadata/Metadata" mode="assets"/>
    </xsl:result-document>
    <xsl:result-document href="{concat($jobName, '_flows.xml')}">
        <xsl:apply-templates select="GetMetadata/Metadata" mode="flows"/>
    </xsl:result-document>

to my xsl map [writing to the files works fine]

LATER

Correct implementation: (thank you Michael)

public void multipleXMLExtractor(Document inputDom, String xsltPath) throws TransformerException, UnsupportedEncodingException {

Source xmlInput = new DOMSource(inputDom);
Source xsltMap = new StreamSource(new File(xsltPath));
final Map<String, StreamResult> resultsMap = new HashMap<String, StreamResult>();
resultsMap.put("output1", new StreamResult(new ByteArrayOutputStream()));
resultsMap.put("output2", new StreamResult(new ByteArrayOutputStream()));

TransformerFactory tFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", XMLviaXSLTransformer.class.getClassLoader());
Transformer transformer = tFactory.newTransformer(xsltMap);
((net.sf.saxon.jaxp.TransformerImpl) transformer).getUnderlyingController().setOutputURIResolver(new OutputURIResolver() {
    @Override
    public OutputURIResolver newInstance() {
        return this;
    }

    @Override
    public Result resolve(String s, String s1) throws TransformerException {
        return resultsMap.get(s);
    }

    @Override
    public void close(Result result) throws TransformerException {
    }
});

StreamResult standardResult = new StreamResult(new ByteArrayOutputStream());
transformer.transform(xmlInput, standardResult);


for (Map.Entry<String, StreamResult> stringStreamResultEntry : resultsMap.entrySet()) {
    System.out.println(stringStreamResultEntry.getKey() + ": " + ((ByteArrayOutputStream) stringStreamResultEntry.getValue().getOutputStream()).toString("UTF-8"));
}

}

1条回答
一夜七次
2楼-- · 2019-08-23 11:55

You need to define an OutputURIResolver - this is a Saxon-specific interface that is called to determine the destination for the output of xsl:result-document. It is given a URI as input, and returns a JAXP Result object to which the result document will be written.

https://www.saxonica.com/documentation/index.html#!javadoc/net.sf.saxon.lib/OutputURIResolver

If you're using the JAXP API to control the transformation, you will have to cast the Transformer object to net.sf.saxon.jaxp.TransformerImpl, and then call getUnderlyingController().setOutputURIResolver(), supplying your OutputURIResolver as the argument.

查看更多
登录 后发表回答