How to avoid encoding of <,>,& with Document.createTextNode - java

class XMLencode
{
public static void main(String[] args)
{
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElement("roseindia");
doc.appendChild(root);
Text elmnt=doc.createTextNode("<data>sun</data><abcdefg/><end/>");
root.appendChild(elmnt);
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource(doc);
Result dest = new StreamResult(System.out);
aTransformer.transform(src, dest);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
Here is my above piece of code.
The output generated is like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?><roseindia><data>sun</data><abcdefg/><end/></roseindia>
I dont want the tags to be encoded. I need the output in this fashion.
<?xml version="1.0" encoding="UTF-8" standalone="no"?><roseindia><data>sun</data><abcdefg/><end/></roseindia>
Please help me on this.
Thanks,
Mohan

Short Answer
You could leverage the CDATA mechanism in XML to prevent characters from being escaped. Below is an example of the DOM code:
doc.createCDATASection("<foo/>");
The content will be:
<![CDATA[<foo/>]]>
LONG ANSWER
Below is a complete example of leveraging a CDATA section using the DOM APIs.
package forum12525152;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
public class Demo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element rootElement = document.createElement("root");
document.appendChild(rootElement);
// Create Element with a Text Node
Element fooElement = document.createElement("foo");
fooElement.setTextContent("<foo/>");
rootElement.appendChild(fooElement);
// Create Element with a CDATA Section
Element barElement = document.createElement("bar");
CDATASection cdata = document.createCDATASection("<bar/>");
barElement.appendChild(cdata);
rootElement.appendChild(barElement);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
t.transform(source, result);
}
}
Output
Note the difference in the foo and bar elements even though they have similar content. I have formatted the result of running the demo code to make it more readable:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<foo><foo/></foo>
<bar><![CDATA[<bar/>]]></bar>
</root>

Instead of writing like this doc.createTextNode("<data>sun</data><abcdefg/><end/>");
You should create each element.
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
class XMLencode {
public static void main(String[] args) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElement("roseindia");
doc.appendChild(root);
Element data = doc.createElement("data");
root.appendChild(data);
Text elemnt = doc.createTextNode("sun");
data.appendChild(elemnt);
Element data1 = doc.createElement("abcdefg");
root.appendChild(data1);
//Text elmnt = doc.createTextNode("<data>sun</data><abcdefg/><end/>");
//root.appendChild(elmnt);
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource(doc);
Result dest = new StreamResult(System.out);
aTransformer.transform(src, dest);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}

You can use the doc.createTextNode and use a workaround (long) for the escaped characters.
SOAPMessage msg = messageContext.getMessage();
header.setTextContent(seched);
Then use
Source src = msg.getSOAPPart().getContent();
To get the content, the transform it to string
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer. setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StreamResult result1 = new StreamResult(new StringWriter());
transformer.transform(src, result1);
Replace the string special characters
String xmlString = result1.getWriter().toString()
.replaceAll("<", "<").
replaceAll(">", ">");
System.out.print(xmlString);
the oposite string to dom with the fixed escaped characters
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlString));
Document doc = db.parse(is);
Source src123 = new DOMSource(doc);
Then set it back to the soap message
msg.getSOAPPart().setContent(src123);

Don't use createTextNode - the whole point of it is to insert some text (as data) into the document, not a fragment of raw XML.
Use a combination of createTextNode for the text and createElement for the elements.

I dont want the tags to be encoded. I need the output in this fashion.
Then you don't want a text node at all - which is why createTextNode isn't working for you. (Or rather, it's working fine - it's just not doing what you want). You should probably just parse your XML string, then import the document node from the result into your new document.
Of course, if you know the elements beforehand, don't express them as text in the first place - use a mixture of createElement, createAttribute, createTextNode and appendChild to create the structure.
It's entirely possible that something like JDOM will make this simpler, but that's the basic approach.

Mohan,
You can't use Document.createTextNode(). That methos transforms (or escapes) the charactes in your XML.
Instead, you need to build two separate Documents from the 2 XML's and use importNode.
I use Document.importNode() like this to solve my problem:
Build your builders:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document oldDoc = builder.parse(isOrigXml); //this is XML as InputSource
Document newDoc = builder.parse(isInsertXml); //this is XML as InputSource
Next, build a NodeList of the Element/Node you want to import. Create a Node from the NodeList. Create another Node of what you are going to import using importNode. Build the last Node of the final XML as such:
NodeList nl = newDoc.getElementByTagName("roseindia"); //or whatever the element name is
Node xmlToInsert = nl.item(0);
Node importNode = oldDoc.importNode(xmlToImport, true);
Node target = ((NodeList) oldDoc.getElementsByTagName("ELEMENT_NAME_OF_LOCATION")).item(0);
target.appendChild(importNode);
Source source = new DOMSource(target);
....
The rest is standard Transformer - StringWriter to StreamResult stuff to get the results.

Related

Adding linebreak in xml file before root node

I am trying to add line break after my comments above the root node in XML document.
I need something like this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE-->
<projects>
</projects>
But What I was able to get is this(Line break inside the root but I need line break after the comment):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE--><projects>
</projects>
I need to add the line break just after my comment. Is there a way to do this?
My code:
import java.io.File;
import java.io.FileInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
public class XMLNewLine {
/**
* #param args
*/
public static void main(String[] args) {
System.out.println("Adding comment..");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db;
try {
Document doc;
StreamResult result;
result = new StreamResult(new File("abc.xml"));
db = dbf.newDocumentBuilder();
doc = db.parse(new FileInputStream(new File("abc.xml")));
Element element = doc.getDocumentElement();
Text lineBreak = doc.createTextNode("\n");
element.appendChild(lineBreak);
Comment comment = doc
.createComment("DO NOT EDIT THIS FILE");
element.getParentNode().insertBefore(comment, element);
doc.getDocumentElement().normalize();
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
}
You basically want a text node containing a line break after the comment node.
Element docElem = doc.getDocumentElement();
doc.insertBefore(doc.createComment("DO NOT EDIT THIS FILE"), docElem);
doc.insertBefore(doc.createTextNode("\\n"), docElem);
EDIT: It seems that appending even whitespace-only text nodes is not allowed at the root node of an org.w3c.dom.Document. This is 100% formally correct, but also unhelpful.
The way comments are rendered in the output of the Transformer is determined by the serializer it uses (there are different serializers for HTML, XML and plain text outputs). In the built-in XML serializer the end of a comment is defined as --> - without a newline.
Since the internals of javax.xml.transform.Transformer are hard-wired, the serializers are not public API and the class is marked as final, overriding that behavior or setting a custom serializer is impossible.
In other words, you are out of luck adding your line break in a clean way.
You can, however, safely add it in a slightly unclean way:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
FileInputStream inputXml = new FileInputStream(new File("input.xml"));
Document doc = db.parse(inputXml);
// add the comment node
doc.insertBefore(doc.createComment("THIS IS A COMMENT"), doc.getDocumentElement());
StringWriter outputXmlStringWriter = new StringWriter();
Transformer transformer = transformerFactory.newTransformer();
// "xml" + "UTF-8" "include XML declaration" is the default anyway, but let's be explicit
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(outputXmlStringWriter));
// now insert our newline into the string & write an UTF-8 file
String outputXmlString = outputXmlStringWriter.toString()
.replaceFirst("<!--", "\n<!--").replaceFirst("-->", "-->\n");
FileOutputStream outputXml = new FileOutputStream(new File("output.xml"));
outputXml.write(outputXmlString.getBytes("UTF-8"));
Doing search-and-replace operations on XML strings is highly discouraged in general, but in this case there is little that can go wrong.
Revisiting this after some time because I had the same issue. I found another solution that does not need to buffer the output in a String:
Write only the XML-declaration by passing an empty document. This will also append a linebreak.
Write the document content without XML-declaration
Code:
StreamResult streamResult = new StreamResult(writer);
// output XML declaration with an empty document
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.transform(new DOMSource(), streamResult);
// output the document without XML declaration
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(doc), streamResult);
You can achieve this by not adding the comment node to your document, but instead partially transforming your document. First transform your own XML processing instruction and comment separately, and then the rest of document:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(new File("abc.xml")));
Result output = new StreamResult(new File("abc.xml"));
Source input = new DOMSource(doc);
// xml processing instruction and comment node
ProcessingInstruction xmlpi = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"");
Comment comment = doc.createComment("DO NOT EDIT THIS FILE");
// first transform the processing instruction and comment
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(xmlpi), output);
transformer.transform(new DOMSource(comment), output);
// then the document
transformer.transform(input, output);
There is a JDK bug concerning this. It was not fixed (as you would expect) because that would likely cause many problems to users' existing applications.
Adding the following output property fixes this:
transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
Had the same issue.
I solved it by putting the comment inside the root element.
Not exactly the same, but I think acceptable.
This is my solution. I just take writer and write to it declaration and the header comment. After that I disable declaration in transformer this way
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
All code:
public static String xmlToTree(String xml, String headerComment) {
try (StringReader reader = new StringReader(xml)) {
StreamResult result = new StreamResult(new StringWriter());
result.getWriter().write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
result.getWriter().write(headerComment + "\n");
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
StreamSource source = new StreamSource(reader);
transformer.transform(source, result);
String xmlTree = result.getWriter().toString();
return xmlTree;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}

Create namespace in dom element issue

Im trying to create XML document with DOM APi's and when i use the following code I got the
expect result
Element rootTreeNode = document.createElementNS("http://schemas.microsoft.com/ado/2007","ex" + ":Ex")
this is the output with tags in output console
ex:Ex Version="1.0" xmlns:ex="http://schemas.microsoft.com/ado/2007"/
Now I want to add to this element the following
**xmlns:gp**="http://www.pst.com/Protocols/Data/Generic"
and I dont succeed with the xmlns:gp i have tried to use
the like the following
rootTreeNode.setAttributeNS("xmlns" ,"gp","http://www.pst.com/Protocols/Data/Generic")
and i have got it like the folloing
**xmlns:ns0="xmlns"** **ns0:gp**="http://www.pst.com/Protocols/Data/Generic"
and if put null in the first parameter
rootTreeNode.setAttributeNS(null ,"gp","http://www.pst.com/Protocols/Data/Generic")
I get just gp with the URL without the xmlns .
what am i doing wrong here ?
Thanks!!!
Complete test:
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElementNS("http://schemas.microsoft.com/ado/2007","ex" + ":Ex");
root.setAttributeNS("http://www.w3.org/2000/xmlns/" ,"xmlns:gp","http://www.pst.com/Protocols/Data/Generic");
doc.appendChild(root);
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(doc);
trans.transform(source, result);
String xmlString = sw.toString();
System.out.println("Xml:\n\n" + xmlString);

How do I append a node to an existing XML file in java

public static void addALLToXML(Collection<Server> svr) throws IOException,
ParserConfigurationException, TransformerException
{
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
Document document = documentBuilder.newDocument();
// Root Element
Element rootElement = document.createElement("Servers");
document.appendChild(rootElement);
for (Server i : svr)
{
// server elements
Element server = document.createElement("server");
rootElement.appendChild(server);
Element name = document.createElement("name");
name.appendChild(document.createTextNode(i.getName()));
server.appendChild(name);
Element port = document.createElement("port");
port.appendChild(document.createTextNode(Integer.toString(i.getPort())));
server.appendChild(port);
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult("/home/user/server.xml");
transformer.transform(source, result);
}
This is the function I need help with:
public static void addNodeToXML(String nameIn, String portIn)
throws ParserConfigurationException, SAXException, IOException
{
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
/* parse existing file to DOM */
Document document = documentBuilder
.parse(new File("/home/user/server.xml"));
// Root Element
Element rootElement = document.createElement("Servers");
document.appendChild(rootElement);
// server elements
Element server = document.createElement("server");
rootElement.appendChild(server);
Element name = document.createElement("name");
name.appendChild(document.createTextNode(nameIn));
server.appendChild(name);
Element port = document.createElement("port");
port.appendChild(document.createTextNode(portIn));
server.appendChild(port);
}
Original:
<Servers>
<server>
<name>something</name>
<port>port</port>
</server>
</Servers>
Wanted:
<Servers>
<server>
<name>something</name>
<port>port</port>
</server>
<server>
<name>something</name>
<port>port</port>
</server>
<Servers>
The following complete example will read an existing server.xml file from the current directory, append a new Server and re-write the file to server.xml. It does not work without an existing .xml file, so you will need to modify the code to handle that case.
import java.util.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
public class AddXmlNode {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("server.xml");
Element root = document.getDocumentElement();
Collection<Server> servers = new ArrayList<Server>();
servers.add(new Server());
for (Server server : servers) {
// server elements
Element newServer = document.createElement("server");
Element name = document.createElement("name");
name.appendChild(document.createTextNode(server.getName()));
newServer.appendChild(name);
Element port = document.createElement("port");
port.appendChild(document.createTextNode(Integer.toString(server.getPort())));
newServer.appendChild(port);
root.appendChild(newServer);
}
DOMSource source = new DOMSource(document);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
StreamResult result = new StreamResult("server.xml");
transformer.transform(source, result);
}
public static class Server {
public String getName() { return "foo"; }
public Integer getPort() { return 12345; }
}
}
Example server.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Servers>
<server>
<name>something</name>
<port>port</port>
</server>
</Servers>
The main change to your code is not creating a new "root" element. The above example just uses the current root node from the existing server.xml and then just appends a new Server element and re-writes the file.
To append a new data element,just do this...
Document doc = docBuilder.parse(is);
Node root=doc.getFirstChild();
Element newserver=doc.createElement("new_server");
root.appendChild(newserver);
easy.... 'is' is an InputStream object. rest is similar to your code....tried it just now...
You can parse the existing XML file into DOM and append new elements to the DOM. Very similar to what you did with creating brand new XML. I am assuming you do not have to worry about duplicate server. If you do have to worry about that, you will have to go through the elements in the DOM to check for duplicates.
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
/* parse existing file to DOM */
Document document = documentBuilder.parse(new File("exisgint/xml/file"));
Element root = document.getDocumentElement();
for (Server newServer : Collection<Server> bunchOfNewServers){
Element server = Document.createElement("server");
/* create and setup the server node...*/
root.appendChild(server);
}
/* use whatever method to output DOM to XML (for example, using transformer like you did).*/
If you need to insert node/element in some specific place , you can to do next steps
Divide original xml into two parts
Append your new node/element as child to first first(the first part should ended with element after wich you wanna add your element )
Append second part to the new document.
It is simple algorithm but should works...
You could use DOM4j doing that.

Bad Characters when parsing GML in Java

I'm using the org.w3c.dom package to parse the gml schemas (http://schemas.opengis.net/gml/3.1.0/base/).
When I parse the gmlBase.xsd schema and then save it back out, the quote characters around GeometryCollections in the BagType complex type come out converted to bad characters (See code below).
Is there something wrong with how I'm parsing or saving the xml, or is there something in the schema that is off?
Thanks,
Curtis
public static void main(String[] args) throws IOException
{
File schemaFile = File.createTempFile("gml_", ".xsd");
FileUtils.writeStringToFile(schemaFile, getSchema(new URL("http://schemas.opengis.net/gml/3.1.0/base/gmlBase.xsd")));
System.out.println("wrote file: " + schemaFile.getAbsolutePath());
}
public static String getSchema(URL schemaURL)
{
try
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(IOUtils.toString(schemaURL.openStream()))));
Element rootElem = doc.getDocumentElement();
rootElem.normalize();
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(doc);
ByteArrayOutputStream xmlOutStream = new ByteArrayOutputStream();
StreamResult result = new StreamResult(xmlOutStream);
transformer.transform(source, result);
return xmlOutStream.toString();
}
catch (Exception e)
{
e.printStackTrace();
}
return "";
}
I'm suspicious of this line:
Document doc = db.parse(new InputSource(
new StringReader(IOUtils.toString(schemaURL.openStream()))));
I don't know what IOUtils.toString does here but presumably it's assuming a particular encoding, without taking account of the XML declaration.
Why not just use:
Document doc = db.parse(schemaURL.openStream());
Likewise your FileUtils.writeStringToFile doesn't appear to specify a character encoding... which encoding does it use, and why encoding is in the StreamResult?

How do I extract child element from XML to a string in Java?

If I have an XML document like
<root>
<element1>
<child attr1="blah">
<child2>blahblah</child2>
<child>
</element1>
</root>
I want to get an XML string with the first child element. My output string would be
<element1>
<child attr1="blah">
<child2>blahblah</child2>
<child>
</element1>
There are many approaches, would like to see some ideas. I've been trying to use Java XML APIs for it, but it's not clear that there is a good way to do this.
thanks
You're right, with the standard XML API, there's not a good way - here's one example (may be bug ridden; it runs, but I wrote it a long time ago).
import javax.xml.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import java.io.*;
public class Proc
{
public static void main(String[] args) throws Exception
{
//Parse the input document
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("in.xml"));
//Set up the transformer to write the output string
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty("indent", "yes");
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
//Find the first child node - this could be done with xpath as well
NodeList nl = doc.getDocumentElement().getChildNodes();
DOMSource source = null;
for(int x = 0;x < nl.getLength();x++)
{
Node e = nl.item(x);
if(e instanceof Element)
{
source = new DOMSource(e);
break;
}
}
//Do the transformation and output
transformer.transform(source, result);
System.out.println(sw.toString());
}
}
It would seem like you could get the first child just by using doc.getDocumentElement().getFirstChild(), but the problem with that is if there is any whitespace between the root and the child element, that will create a Text node in the tree, and you'll get that node instead of the actual element node. The output from this program is:
D:\home\tmp\xml>java Proc
<?xml version="1.0" encoding="UTF-8"?>
<element1>
<child attr1="blah">
<child2>blahblah</child2>
</child>
</element1>
I think you can suppress the xml version string if you don't need it, but I'm not sure on that. I would probably try to use a third party XML library if at all possible.
Since this is the top google answer and For those of you who just want the basic:
public static String serializeXml(Element element) throws Exception
{
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
StreamResult result = new StreamResult(buffer);
DOMSource source = new DOMSource(element);
TransformerFactory.newInstance().newTransformer().transform(source, result);
return new String(buffer.toByteArray());
}
I use this for debug, which most likely is what you need this for
I would recommend JDOM. It's a Java XML library that makes dealing with XML much easier than the standard W3C approach.
public String getXML(String xmlContent, String tagName){
String startTag = "<"+ tagName + ">";
String endTag = "</"+ tagName + ">";
int startposition = xmlContent.indexOf(startTag);
int endposition = xmlContent.indexOf(endTag, startposition);
if (startposition == -1){
return "ddd";
}
startposition += startTag.length();
if(endposition == -1){
return "eee";
}
return xmlContent.substring(startposition, endposition);
}
Pass your xml as string to this method,and in your case pass 'element' as parameter tagname.
XMLBeans is an easy to use (once you get the hang of it) tool to deal with XML without having to deal with the annoyances of parsing.
It requires that you have a schema for the XML file, but it also provides a tool to generate a schema from an exisint XML file (depending on your needs the generated on is probably fine).
If your xml has schema backing it, you could use xmlbeans or JAXB to generate pojo objects that help you marshal/unmarshal xml.
http://xmlbeans.apache.org/
https://jaxb.dev.java.net/
As question is actually about first occurrence of string inside another string, I would use String class methods, instead of XML parsers:
public static String getElementAsString(String xml, String tagName){
int beginIndex = xml.indexOf("<" + tagName);
int endIndex = xml.indexOf("</" + tagName, beginIndex) + tagName.length() + 3;
return xml.substring(beginIndex, endIndex);
}
You can use following function to extract xml block as string by passing proper xpath expression,
private static String nodeToString(Node node) throws TransformerException
{
StringWriter buf = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
xform.transform(new DOMSource(node), new StreamResult(buf));
return(buf.toString());
}
public static void main(String[] args) throws Exception
{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
XPath xPath = XPathFactory.newInstance().newXPath();
Node result = (Node)xPath.evaluate("A/B/C", doc, XPathConstants.NODE); //"A/B[id = '1']" //"//*[#type='t1']"
System.out.println(nodeToString(result));
}

Categories