Project

Profile

Help

Glassfish using Saxon instead of Xalan, XSLT 2.0, Java

Added by Eri Aute over 10 years ago

I have a problem with transforming a XML (TEI P5) to PDF. My Stylesheet is from TEI https://github.com/TEIC/Stylesheets and I call the file fo/fo.xsl. When I transform my XML using Oxygen and Saxon there is no Problem, the PDF will be generated. But in my J2EE application the transform does not work. I think because of the XSLT 2.0. So i wanted to change to an other parser. I downloaded Saxon 9HE and included it in my project. Then I experimented and changed the java call and it looks now like this:


 String inputXSL2 = "/de/we/parser/xslt/fo/fo.xsl";
    String inputXML2 = "/de/we/parser/testfiles/Presentation.xml";

    Source xsltTarget = new StreamSource(inputXSL2);
    try {
        TransformerFactory tFactory = TransformerFactory.newInstance();
        tFactory.setURIResolver(new XsltURIResolver());
        Transformer transformer = tFactory.newTransformer(xsltTarget);
        Controller controller = (net.sf.saxon.Controller) transformer;
        Configuration configuration = controller.getConfiguration();
        configuration.setConfigurationProperty(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION, Boolean.TRUE);

        Source source = transformer.getURIResolver().resolve(inputXML2, "");
        DocumentInfo newdoc = configuration.buildDocument(source);
        configuration.getGlobalDocumentPool().add(newdoc, inputXML2);

        Source streamSource = null;
        StreamResult resultTarget = null;

        streamSource = new StreamSource(new StringReader(inputXML2));
        resultTarget = new StreamResult(new StringWriter());
        transformer.transform(streamSource, resultTarget);
    } catch (Exception e) {
        System.out.println(e);
    }


class XsltURIResolver implements URIResolver {

@Override
public Source resolve(String href, String base) throws TransformerException {
    try {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("/de/we/parser/xslt/fo/" + href);
        StreamSource ss = new StreamSource(inputStream);
        ss.setSystemId("/de/we/parser/xslt/fo/" + href);
        return ss;
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}
}

The error is: I/O error reported by XML parser processing /de/we/parser/xslt/fo/fo.xsl: \de\we\parser\xslt\fo\fo.xsl (Das System kann den angegebenen Pfad nicht finden) But the file exists so i don't know whats the problem.

Had a lot other version where I tried to use Saxon, but the result was never a generated pdf :( Need some help please


Replies (4)

Please register to reply

RE: Glassfish using Saxon instead of Xalan, XSLT 2.0, Java - Added by Michael Kay over 10 years ago

The SystemId should be a URI, not a filename. Try adding "file://" at the front.

Michael Kay Saxonica

RE: Glassfish using Saxon instead of Xalan, XSLT 2.0, Java - Added by Michael Kay over 10 years ago

Alternatively, do

Source xsltTarget = new StreamSource(new File(inputXSL2));

(and you could also check File.exists()).

Doing it this way means you set the input stream and the system ID at the same time. Setting a StreamSource with no system ID is a bad idea because it means relative URIs in xxl:include/xsl:import can't be resolved.

RE: Glassfish using Saxon instead of Xalan, XSLT 2.0, Java - Added by Eri Aute over 10 years ago

I did the File.exists() and the URI. But I had to change a lot because I had a lot of NullpointerExceptions because the program had problems with the file structure. Now the code is:


 public void parseXMLToPDF(OutputStream output) throws Exception {
        String outputPDFPrefix = "we_output";
        String outputPDFSuffix = "pdf";
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        Fop fop = FopFactory.newInstance().newFop(MimeConstants.MIME_PDF, byteArrayOutputStream);
        Result sax = new SAXResult(fop.getDefaultHandler());
    
        String inputXSL2 = "/de/we/parser/xslt/fo/fo.xsl";
        String inputXML2 = "/de/we/parser/testfiles/Presentation.xml";

        File f = new File(getClass().getResource(inputXSL2).toURI());
        System.out.println(f.exists());
        Source xsltTarget = new StreamSource(f);
        try {
            TransformerFactory tFactory = TransformerFactory.newInstance();
            tFactory.setURIResolver(new XsltURIResolver());
            Transformer transformer = tFactory.newTransformer(xsltTarget);
            Controller controller = (net.sf.saxon.Controller) transformer;
            Configuration configuration = controller.getConfiguration();
            configuration.setConfigurationProperty(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION, Boolean.TRUE);

            Source source = transformer.getURIResolver().resolve(inputXML2, "");
            DocumentInfo newdoc = configuration.buildDocument(source);
            configuration.getGlobalDocumentPool().add(newdoc, inputXML2);

            Source streamSource = null;
            StreamResult resultTarget = null;

            streamSource = new StreamSource(new StringReader(inputXML2));
            resultTarget = new StreamResult(new StringWriter());
            transformer.transform(streamSource, sax);
        } catch (Exception e) {
            System.out.println(e);
        }


        File tempFile = File.createTempFile(outputPDFPrefix, outputPDFSuffix);
        logger.log(Level.INFO, "Saved PDF: {0}", tempFile.getAbsolutePath());
        byte[] generatedPdf = byteArrayOutputStream.toByteArray();
        output.write(generatedPdf);
        OutputStream pdf = new FileOutputStream(tempFile);
        pdf.write(generatedPdf);
        pdf.close();
    }


class XsltURIResolver implements URIResolver {

    @Override
    public Source resolve(String href, String base) throws TransformerException {
        try {
            String path = "/de/we/parser/xslt/";
            String begin = "";
            String str = "";
            if (base.length() > 0) {
                begin = base.substring(base.lastIndexOf(path) + path.length(), base.lastIndexOf('/'));
                str = path + begin + "/" + href;
            } else {
                str = href;
            }
            System.out.println(str);
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(str);
            StreamSource ss = new StreamSource(inputStream);
            ss.setSystemId(getClass().getResource(str).toURI().toString());
            return ss;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
}

But when the programm computes the line
transformer.transform(streamSource, sax); it throws the exception:

INFO: net.sf.saxon.trans.XPathException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content ist nicht zulässig in Prolog. (Content is not allowed in prolog)
	at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:420)
	at net.sf.saxon.event.Sender.send(Sender.java:169)
	at net.sf.saxon.Controller.transform(Controller.java:1890)
	at de.wedekind.parser.ParserImpl.parseXMLToPDF(ParserImpl.java:739)

RE: Glassfish using Saxon instead of Xalan, XSLT 2.0, Java - Added by Michael Kay over 10 years ago

Manipulating paths like this using string concatenation really doesn't seem a very good idea; you're introducing a lot of potential for error. I can't see why it's all so complicated.

You've used "new File()" as I suggested to pick up the XSLT stylesheet, and this appears to be working OK. So you just need to pick up the XML source document the same way.

The error message is a bit of a catch-all from Xerces saying that it the input stream you've passed to the parser doesn't look like XML. You might find it useful to try invoking the parser with Saxon out of the loop, just to reduce the number of variables.

    (1-4/4)

    Please register to reply