How can I create an InputStream object from a XML Document or Node object to be used in xstream? I need to replace the ??? with some meaningful code. Thanks.
Document doc = getDocument();
InputStream is = ???;
MyObject obj = (MyObject) xstream.fromXML(is);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(doc);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
If you are using Java without any Third Party Libraries, you can create InputStream using below code:
/*
* Convert a w3c dom node to a InputStream
*/
private InputStream nodeToInputStream(Node node) throws TransformerException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Result outputTarget = new StreamResult(outputStream);
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.transform(new DOMSource(node), outputTarget);
return new ByteArrayInputStream(outputStream.toByteArray());
}
One way to do it: Adapt the Document to a Source with DOMSource. Create a StreamResult to adapt a ByteArrayOutputStream. Use a Transformer from TransformerFactory.newTransformer to copy across the data. Retrieve your byte[] and stream with ByteArrayInputStream.
Putting the code together is left as an exercise.
public static InputStream document2InputStream(Document document) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputFormat outputFormat = new OutputFormat(document);
XMLSerializer serializer = new XMLSerializer(outputStream, outputFormat);
serializer.serialize(document);
return new ByteArrayInputStream(outputStream.toByteArray());
}
This works if you are using apache Xerces implementation, you can also set format parameter with the output format.
public static InputStream documentToPrettyInputStream(Document doc) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
XMLWriter xmlWriter = new XMLWriter(outputStream, OutputFormat.createPrettyPrint());
xmlWriter.write(doc);
xmlWriter.close();
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return inputStream;
}
If you happen to use DOM4j and you need to print it pretty!
Related
I have an InputStream containing a SOAP message, including the envelope. I don't know the contents of the body beforehand and therefore cannot create a Jaxb annotated class for it.
I've tried many ways, inlcuding a custom SOAPWrapper JaxB Class with XmlAnyElement and other ways. Currently I have this:
private InputStream removeSoapEnvelope(final InputStream inputStream) throws IOException, TransformerException
{
final SoapBody body = messageFactory.createWebServiceMessage(inputStream)
.getSoapBody();
final Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
final DOMResult domResult = new DOMResult();
transformer.transform(body.getPayloadSource(), domResult);
final StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(domResult.getNode()), new StreamResult(writer));
byte[] barray = writer.toString()
.getBytes(StandardCharsets.UTF_8);
return new ByteArrayInputStream(barray);
}
It seems to work but is horribly inefficient. Is there no short and concise way of achieving this with standard libraries and without regex?
Thanks
Here's a solution using XPath to get the element (pure JaxB? not sure). Takes the document as a regular XML document so it should work for any I guess
FileInputStream fileIS;
fileIS = new FileInputStream(System.getProperty("user.home") + "/tmp/soap.xml");
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument;
xmlDocument = builder.parse(fileIS);
XPath xPath = XPathFactory.newInstance().newXPath();
String expression01 = "//*[local-name()='Body']";
Node currentNode = (Node) xPath.compile(expression01).evaluate(xmlDocument, XPathConstants.NODE);
StringWriter buf = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
xform.setOutputProperty(OutputKeys.INDENT, "yes");
xform.transform(new DOMSource(currentNode), new StreamResult(buf));
System.out.println(buf.toString());
Result:
<soap:Body>
<incident xmlns="http://example.com">
<Company type="String">Test</Company>
</incident>
</soap:Body>
I ended up doing it with regex. All other options are too slow:
private InputStream removeSoapEnvelope(final InputStream inputStream) throws IOException
{
final String text = new String(inputStream.readAllBytes(), UTF_8);
final String replace = text.replaceAll("\\s*<\\/?(?:SOAP-ENV|soap):(?:.|\\s)*?>", "");
File file = File.createTempFile("temp", XML_NS_PREFIX);
Files.writeString(file.toPath(), replace);
return new FileInputStream(file);
}
I was trying to fix XEE issue and have tried other options but won't work. Would be great if there were any pointers.
Below is my code snippet..
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(feed);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource,outputTarget);
is = new ByteArrayInputStream(outputStream.toByteArray());
Have a look at OWASP XXE Prevention Cheat Sheet
based of what i see in your code, you should modifiy it like this :
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(feed);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
tf.newTransformer().transform(xmlSource,outputTarget);
is = new ByteArrayInputStream(outputStream.toByteArray());
I have a org.w3c.dom.Document and have to zip and base64 encode it to send it with the EBICS protocol via HTTP/HTTPS
I tried
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(doc);
Result outputTarget = new StreamResult(outputStream);
TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
InputStream inflated_stream = new InflaterInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
final byte[] bytes64bytes = Base64.encodeBase64(IOUtils.toByteArray(inflated_stream));
OrderData = new String(bytes64bytes);
but get an exception
java.util.zip.ZipException: incorrect header check
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:164)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1025)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:999)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:218)
I haven't tried this, but wouldn't the following do what you need?
OutputStream outputStream = new ZipOutputStream(new ByteArrayOutputStream());
I think your problem might be down to the use of InflaterInputStream - aren't you trying to deflate this stream? You code may work if you just change InflaterInputStream to DeflaterInputStream
Changing
InputStream inflated_stream = new InflaterInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
to
InputStream inflated_stream = new DeflaterInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
solved the issue
Thanks
I am new to javax.xml.transform.Transformer.
I am applying an XSLT on an XML document and It works fine.
What I want to achieve is to be able to write the output of that tranformation to an OutputStream.
This is my code:
OutputStream outputStream = null;
InputStream agent = new FileInputStream("src/res/testxmlfile.xml");
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(new StreamSource("src/res/trans.xslt"));
transformer.transform(new StreamSource(agent), outputStream ????????);
I know it can be used to write a file like this, but I want to write it to a OutputStream Object.
transformer.transform(new StreamSource(agent),
new StreamResult(new FileOutputStream("/result.xml")));
How can I pass an OutputStream to be used here?
This is the error I am getting when I am passing the Outputstream:
Exception in thread "main" javax.xml.transform.TransformerException:
Result object passed to ''{0}'' is invalid.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
.getOutputHandler(TransformerImpl.java:468)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
.transform(TransformerImpl.java:344)
at com.gohealth.TestXmlStream.main(TestXmlStream.java:75)
Use a StreamResult. It provides constructors to write to a File or an OutputStream:
Example using File:
transformer.transform(new StreamSource(agent), new StreamResult(file));
Example using FileOutputStream:
FileOutputStream outputStream = new FileOutputStream(new File("outputfile.xml"));
transformer.transform(new StreamSource(agent), new StreamResult(outputStream));
Example using ByteArrayOutputStream:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
transformer.transform(new StreamSource(agent), new StreamResult(outputStream));
byte[] bytes = outputStream.toByteArray();`
Use a "StreamResult" constructed with an object that represents where you want the output. See http://docs.oracle.com/javase/7/docs/api/javax/xml/transform/stream/StreamResult.html
I am trying to read xml data from Document Object, and then using transformer to render the data inside the document object to pdf,using XSL,
My code is :
Document doc = toXML(arg1,arg2);
doc contains data like :
İlkyönetmeliği
with in tags
InputStream inputStream = new FileInputStream(xslFilePath);
transformer = factory.newTransformer(new StreamSource(inputStream));
transformer.setParameter("encoding", "UTF-8");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc.getDocumentElement()), res);
Special characters present in xml are not getting rendered accordingly and displaying like
#lk yard#m.
I have also set encoding to UTF-8 ,but still it is displaying like above.
It is not clear what causes your encoding problem because I cannot see how your document is read/constructed and how your transformation result res is set up. Try the following standalone example code which handles encoding with XSLT. Maybe you can even modify it gradually to use your actual data in order to see what goes wrong.
public static void main(String[] args) {
try {
String inputEncoding = "UTF-16";
String xsltEncoding = "ASCII";
String outputEncoding = "UTF-8";
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(bos, inputEncoding);
osw.write("<?xml version='1.0' encoding='" + inputEncoding + "'?>");
osw.write("<root>İlkyönetmeliği</root>"); osw.close();
byte[] inputBytes = bos.toByteArray();
bos.reset();
osw = new OutputStreamWriter(bos, xsltEncoding);
osw.write("<?xml version='1.0' encoding='" + xsltEncoding + "'?>");
osw.write("<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>");
osw.write("<xsl:template match='#*|node()'><xsl:copy><xsl:apply-templates select='#*|node()'/></xsl:copy></xsl:template>");
osw.write("</xsl:stylesheet>"); osw.close();
byte[] xsltBytes = bos.toByteArray();
bos.reset();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document d = db.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(inputBytes), inputEncoding)));
// if encoding declaration correct, use: Document d = db.parse(new InputSource(new ByteArrayInputStream(inputBytes)));
System.out.println(XPathFactory.newInstance().newXPath().evaluate("/root[1]", d));
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer(new StreamSource(new InputStreamReader(new ByteArrayInputStream(xsltBytes), xsltEncoding)));
// if encoding declaration correct, use: Transformer t = tf.newTransformer(new StreamSource(new ByteArrayInputStream(xsltBytes)));
StreamResult sr = new StreamResult(new OutputStreamWriter(bos, outputEncoding));
t.setOutputProperty(OutputKeys.ENCODING, outputEncoding);
t.transform(new DOMSource(d.getDocumentElement()), sr);
byte[] outputBytes = bos.toByteArray();
Scanner s = new Scanner(new InputStreamReader(new ByteArrayInputStream(outputBytes), outputEncoding));
String output = s.useDelimiter("</>").next(); // read all
s.close();
System.out.println(output);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
The example code applies the XSLT identity template to a minimal input containing the non-ASCII characters.
I output the string to check if it has been parsed correctly in the document using XPath. You may want to check your (intermediate) document if you know how to locate it with XPath.
Note that, if present, the parser tries to pick up the encoding declared in the XML processing instruction (PI) by default when reading an XML file. It assumes that actual and declared encoding are the same. If they differ or the PI is missing, then you can enforce the actual encoding e.g. by using an InputStreamReader as in the code above.