Jeff Holt
Jeff Holt

Reputation: 3190

Is net.sf.saxon.s9api.XsltTransformer designed for one time use?

I don't believe I adequately understand the XsltTransformer class enough to explain why method f1 is superior to f2. In fact, f1 finishes in about 40 seconds, consuming between 750mb and 1gb of memory. I was expecting f2 to be a better solution but it never finishes for the same lengthy list of input files. By the time I kill it, it has processed only about 1000 input files while consuming over 4gb of memory.

import java.io.*;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.*;
public class foreachfile {
    private static long f1 (Processor p, XsltExecutable e, Serializer ser, String args[]) {
        long maxTotalMemory = 0;
        Runtime rt = Runtime.getRuntime();
        for (int i=1; i<args.length; i++) {
            String xmlfile = args[i];
            try {
                XsltTransformer t = e.load();
                t.setDestination(ser);
                t.setInitialContextNode(p.newDocumentBuilder().build(new StreamSource(new File(xmlfile))));
                t.transform();
                long tm = rt.totalMemory();
                if (tm > maxTotalMemory)
                    maxTotalMemory = tm;
            } catch (Throwable ex) {
                System.err.println(ex);
            }
        }
        return maxTotalMemory;
    }
    private static long f2 (Processor p, XsltExecutable e, Serializer ser, String args[]) {
        long maxTotalMemory = 0;
        Runtime rt = Runtime.getRuntime();
        XsltTransformer t = e.load();
        t.setDestination(ser);
        for (int i=1; i<args.length; i++) {
            String xmlfile = args[i];
            try {
                t.setInitialContextNode(p.newDocumentBuilder().build(new StreamSource(new File(xmlfile))));
                t.transform();
                long tm = rt.totalMemory();
                if (tm > maxTotalMemory)
                    maxTotalMemory = tm;
            } catch (Throwable ex) {
                System.err.println(ex);
            }
        }
        return maxTotalMemory;
    }
    public static void main (String args[]) throws SaxonApiException, Exception {
        String usecase = System.getProperty("xslt.usecase");
        int uc = Integer.parseInt(usecase);
        String xslfile = args[0];
        Processor p = new Processor(true);
        XsltCompiler c = p.newXsltCompiler();
        XsltExecutable e = c.compile(new StreamSource(new File(xslfile)));
        Serializer ser = new Serializer();
        ser.setOutputStream(System.out);
        long maxTotalMemory = uc == 1  ?  f1(p, e, ser, args)  :  f2(p, e, ser, args);
        System.err.println(String.format("Max total memory was %d", maxTotalMemory));
    }
}

Upvotes: 0

Views: 240

Answers (1)

Michael Kay
Michael Kay

Reputation: 163468

I normally recommend using a new XsltTransformer for each transformation. However, the class is serially reusable (you can perform multiple transformations one after another, but not concurrently). The XsltTransformer keeps certain resources in memory, in case they are needed again: notably, all documents read using the doc() or document() functions. This can be useful, for example, if you want to transform one set of input documents to five different output formats as part of your publishing workflow. But if this reuse of resources doesn't give you any benefits, it merely imposes a cost in memory use, which you can avoid by creating a new transformer each time. The same applies if you use the JAXP interface.

Upvotes: 1

Related Questions