Transforming a StAX Source in Java - java

I have some code like:
XMLInputFactory xif = XMLInputFactory.newInstance()
TransformerFactory tf = TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl", null)
Transformer t = tf.newTransformer()
DOMResult result = new DOMResult()
t.transform(new StAXSource(reader), result)
Which produces the following error:
Caught: javax.xml.transform.TransformerException: Can't transform a Source of type javax.xml.transform.stax.StAXSource
The reader object is of type com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl

So I was stupidly trying the wrong thing. This fixed it:
System.setProperty("javax.xml.transform.TransformerFactory",
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");

I stumbled upon Xml Transformer give me an error when trying to transform a StaxSource into a StreamResult, while looking to solve the very same issue as you.
The answer provided there seems to be working fine for me, i.e. use:
TransformerFactory.newDefaultInstance();
Instead of:
XMLInputFactory.newInstance()

Related

Errors creating html file using xml and xsl file (xslt 2.0) (Recoverable error I/O error reported by XML parser processing)

Im using the code below to generate html from a xml and xsl files. It was working fine for xslt 1.0, but now Im using xslt 2.0. And Im getting this error when execute the code below: ERROR: Unsupported XSL element 'for-each-group'.'
Do you know how to fix this?
private static void createHtml(){
try {
TransformerFactory tf =TransformerFactory.newInstance();
Source xslFile =new StreamSource("test.xsl");
Source xmlFile =new StreamSource(new StringReader(xml));
String resultFile ="test.html";
OutputStream htmlFile=new FileOutputStream(resultFile );
Transformer trasform=tFactory.newTransformer(xslFile);
trasform.transform(xmlFile, new StreamResult(htmlFile));
}
catch (Exception e)
{
System.out.println("Error.");
}
}
Im trying to do like this now:
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer transformer = tfactory.newTransformer(new StreamSource(new File("test.xsl")));
transformer.transform(new StreamSource(new File(xml)),
new StreamResult("test.html"));
And in the main method:
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl")
And I get this error:
Recoverable error
I/O error reported by XML parser processing
Any idea how to fix this?
You're reporting two different errors:
(a) ERROR: Unsupported XSL element 'for-each-group'.'
(b) Recoverable error: I/O error reported by XML parser processing
It seems unlikely that you got these from the same run, so it's not clear what you were doing on each of these occasions to get two different errors.
The first error means that for some reason you have loaded an XSLT processor that doesn't support XSLT 2.0. The safest and fastest way to be sure of loading Saxon is to instantiate it directly:
TransformerFactory tfactory = new net.sf.saxon.TransformerFactoryImpl();
If you rely on the JAXP mechanisms there are all sorts of things that can go wrong, and it can also be very slow because it involves searching the classpath.
With the second error, you haven't given enough information to provide a full diagnosis. However, the fact that there's no filename in the message gives a clue: it means Saxon doesn't know the filename, and this is often because you have done something like:
Source xmlFile =new StreamSource(new StringReader(xml));
A StringReader itself will never give an I/O error. But if the XML that you are parsing contains a DTD reference, or references to other external entities, and if these are relative references, then the XML parser won't be able to resolve them because it doesn't have a base URI to work with. You can supply a base URI in the second argument of the StreamSource constructor.

Prevent XXE fortify issue for TrasnformerFactory

I need to fix XXE issue .I am using transformerfactory in code.
Found below fix but i can not see ACCESS_EXTERNAL_DTD attribute in my code.Reason which i got is below code will work for Java7 however i am using Java 6 .Can some one please suggest some other fix
To protect a Java TransformerFactory from XXE, do this:
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
I was in to same situation and it is difficult to resolve without updating Java version.
Following is code change that was able to pass fortify scan with same results.
Instead of using TransformerFactory use following code:
DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation();
LSSerializer lsSerializer = domImplementation.createLSSerializer();
LSOutput lsOutput = domImplementation.createLSOutput( );
lsOutput.setEncoding("UTF-8");
StringWriter stringWriter=new StringWriter();
lsOutput.setCharacterStream(stringWriter);
lsSerializer.write(doc,lsOutput);
return stringWriter.toString();
For reference please review Is there a more elegant way to convert an XML Document to a String in Java than this code?.
And

Transforming Streaming XSLT Without a Custom Content Handler

Take a look at this website:
http://xmpp.wordpress.com:8008/firehose.xml?type=text/plain
It constantly streams data. You can transform this content using the newest version of XSLT (v3), with a command like this:
<xsl:stream href="http://xmpp.wordpress.com:8008/firehose.xml?type=text/plain">
If I want to write some Java code to initiate the transformation (using Saxon, which has implemented xsl:stream), I can do this:
// XSL
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(new StreamSource(new FileInputStream(xslFile)));
// XML
StreamSource xmlSource = new StreamSource(new FileInputStream(xmlFile));
// Output
MyCustomContentHandler handler = new MyCustomContentHandler();
PrintStream outputPrintStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile)), true);
handler.setPrintStream(outputPrintStream);
Result result = new SAXResult(handler);
// Transform
transformer.transform(xmlSource, result);
This works. If you let it run for a bit, then open the output file, you’ll see data in it. If you re-open it a bit later, you’ll see even more data. The key to this is the custom content handler that processes the various SAX events.
But suppose that I don’t really want a custom content handler. Suppose I just want to keep the output of the XSLT as is. I can modify my code like this:
// XSL
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(new StreamSource(new FileInputStream(xslFile)));
// XML
StreamSource xmlSource = new StreamSource(new FileInputStream(xmlFile));
// Output
TransformerHandler transformerHandler = ((SAXTransformerFactory) SAXTransformerFactory.newInstance()).newTransformerHandler();
transformerHandler.setResult(new StreamResult(new PrintWriter(new FileOutputStream(outputFile, true), true)));
// or this…
//transformerHandler.setResult(new StreamResult(new FileOutputStream(outputFile)));
// or this…
//transformerHandler.setResult(new StreamResult(new FileWriter(outputFile)));
ContentHandler contentHandler = (ContentHandler) transformerHandler;
SAXResult result = new SAXResult(transformerHandler);
// Transform
transformer.transform(xmlSource, result);
The good news is that I no longer need a custom content handler, and my output now matches the output of the XSLT exactly. The bad news is that although this code works with non-streaming XSLT, it does not work with streaming XSLT. Despite my various attempts at setting the result (see the “or this…” statements above), nothing is written to the file. I suspect there’s a buffering problem of some sort.
Question: How can I combine the best of these two together? How can I transform a streaming XSLT without having to use a custom content handler?
This seems to be a rerun of a thread on the saxon-help list in June:
http://sourceforge.net/p/saxon/mailman/message/32472658/
The conclusion there was that the output was somehow being buffered in the output stream pipeline. Saxon is emitting events representing the transformation result, as you see by supplying a ContentHandler, but the serialization of these events is being buffered in the I/O system.
At this time, it does not appear to be possible to do what I want to do. My current solution is to use a custom content handler (per my question above) and run its results through a standard XSLT identity transformation. A bit ugly and not very efficient, but it works.

XSL validation while transformation

I'm using the following piece of code to do XSL transformation :
Source source = new StreamSource(new StringReader(request.toString()));
Source xsl = new StreamSource(XSLPath);
StringWriter destination = new StringWriter();
Result result = new StreamResult(destination);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer;
transformer = transFactory.newTransformer(xsl);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
The XSLPath variable passes the file location to the .xsl file.
I need to know whether the transFactory.newTransformer(xsl) does any kind of internal validation first of the xsl file itself. If not, then is there a way we can do validation of the xsl file, before performing the transformation?
I have a code to validate an xsd file, but, I believe the same code wouldn't work for an xsl. I still tried that as well, but it always throw some or the other SAXException about Non-white spaces not being allowed on most of the lines.
Yes, the first thing the XSLT processor does is to validate and compile the stylesheet. (Why did you have to ask? Just introduce an error, and see what happens!)
You might find it useful to set an ErrorListener to make sure that your application can capture the error messages.
If you are using the same stylesheet repeatedly for many transformations, it is much more efficient to use newTemplates() to create a Templates object so you only do the validation/compilation once. Think of the Templates object as the compiled stylesheet.

How to transform XMLStreamReader to XMLStreamWriter

Should be easy and obvious but I cant find a way - the XMLOutputFactory accepts anly OutputStream, Result or another Writer to generate a new XMLStreamWriter. What I have at hand is an XMLStreamReader which has no methods for extracting a Result or an OutputStream.
If the solution would be easier using the Event API, that would be OK too.
Thank you
You could use a javax.xml.transform.Transformer to convert a StAXSource wrapping the reader to a StAXResult wrapping the writer.
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
StAXSource source = new StAXSource(xmlStreamReader);
StAXResult result = new StAXResult(xmlStreamWriter);
t.transform(source, result);
Using the Event API you could also use the folloiwng:
http://download.oracle.com/javase/6/docs/api/javax/xml/stream/XMLEventWriter.html#add(javax.xml.stream.XMLEventReader)

Categories

Resources