0

I know that I can pass parameters from Java into an xsl transform, but how can I read variables/parameters back out after the transform is complete?

For example, I have an xml document like this:

<author>
  <name>Barry Bonds</name>
  <books>
    <book>Hitting Home Runs</book>
    <book>Cheating at Baseball</book>
    <book>Nobody Likes Cooperstown Anyway</book>
  <books>
<author>

In a single transform, I'd like to be able to transform the name element and store that as a variable and also transform the book elements and store them as a second variable. Then I would like to get access to those 2 variables from Java code, after the transform.

Is this possible, and if so, how is it done?

Thanks to Michael Kay's answer, I now have a solution. For others who come across this, here's a unit test showing how it works:

import net.sf.saxon.*;
import org.junit.Test;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertEquals;

public class SimpleTransform {
    @Test
    public void splitOutput() throws TransformerException, UnsupportedEncodingException {
        final Map<String, StreamResult> results = new HashMap<String, StreamResult>();
        results.put("test1", new StreamResult(new ByteArrayOutputStream()));
        results.put("test2", new StreamResult(new ByteArrayOutputStream()));
        results.put("test3", new StreamResult(new ByteArrayOutputStream()));

        TransformerFactoryImpl factory = new TransformerFactoryImpl();
        Source source = new StandardURIResolver(new Configuration()).resolve("transform.xslt", null);
        Controller xsl = (Controller) factory.newTransformer(source);
        xsl.setOutputURIResolver(new OutputURIResolver() {
            @Override
            public Result resolve(String s, String s1) throws TransformerException {
                return results.get(s);
            }

            @Override
            public void close(Result result) throws TransformerException {
            }
        });
        Source xsd = (Source) Transform.loadDocuments("input.xml", false, null, false);
        StreamResult standardResult = new StreamResult(new ByteArrayOutputStream());
        xsl.transform(xsd, standardResult);

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

        assertEquals("<html>\n   <body>test1</body>\n</html>", ((ByteArrayOutputStream) results.get("test1").getOutputStream()).toString("UTF-8"));
        assertEquals("<html>\n   <body>test2</body>\n</html>", ((ByteArrayOutputStream) results.get("test2").getOutputStream()).toString("UTF-8"));
        assertEquals("<html>\n   <body>test3</body>\n</html>", ((ByteArrayOutputStream) results.get("test3").getOutputStream()).toString("UTF-8"));
    }
}
3
  • Well which of the various Java XSLT processors do you use? And what kind of data type do you expect the transformation result to be that you want in a variable? With XSLT 2.0 it is certainly possible to have one transformation create several result sequences and depending on the API of the XSLT 2.0 processor you will certainly able to store result sequences in variables I guess but it is not clear from your description whether that helps. Commented Jun 1, 2012 at 16:40
  • Currently I'm using the transformer that comes with Java 6 (TransformerFactory.newInstance().newTransformer()). I'm open to recommendations for better ones though. The output I'm looking for would mostly be just multiple strings, so it sounds like this can be done and perhaps I'm just missing something in the api or need a more featureful transformer. Commented Jun 1, 2012 at 17:02
  • ...to add to my last comment. For any suggested transformers, would prefer open source options. Commented Jun 1, 2012 at 17:15

1 Answer 1

2

Switch to XSLT 2.0 (in practice in your case that means Saxon), and generate each output using the xsl:result-document instruction. You can have the result documents delivered back to your Java application by registering an OutputURIResolver with Saxon - a simple class that is notified of each result document as it is created.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your help. I have it working now and have edited the original question to add a sample solution for others to look at.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.