Dynamically insert an XML Element into a text node - java

I'm writing a program in Java where the ultimate goal is to create an XML file from user inputs.
I'm able to predict where almost all of the elements need to be, with one exception.
Any one sentence the user inputs is put into its own Callout tag:
<Callout>The user entered some text.</Callout>
If the sentence contains the phrase "User Guide", the program needs to automatically surround those two words with this XML tag:
<BookTitle></BookTitle>
For example, the initial tag looks like this:
<Callout>Save the User Guide</Callout>
The end result should be:
<Callout>Save the <BookTitle>User Guide</BookTitle>.</Callout>
Note that the term "User Guide" could appear in any location within the "Callout" tag.
I'm not sure how to dynamically add a tag into the middle of a text node. Is that even possible? I tried the solution found here (Convert String XML fragment to Document Node in Java)
but to no avail. I'm using org.w3c.dom to create the elements, nodes, etc.

Don't know exactly how you are constructing your XML document, I assumed the use of some kind of DOM.
This is a VERY simple example of a proof-of-concept. It borrows very heavily from library code, so it may be a little bloated in places, but the basic idea should be reasonable...
Basically, it searches a String for a given token (User Guide) in this case and splits the original text around it, appending #text nodes and <BookTitle> nodes appropriately...
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
public class Main {
public static final String BOOK_TITLE = "User Guide";
public static void main(String[] args) {
Document doc = null;
try {
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element root = doc.createElement("root");
doc.appendChild(root);
// Create callout node...
Element callOut = doc.createElement("CallOut");
// Get the user input...
String text = "This is an example of a User Guide for you to read";
// Does it contain our marker...?
if (text.contains(BOOK_TITLE)) {
// While the text contains the mark, continue looping...
while (text.contains(BOOK_TITLE)) {
// Get the text before the marker...
String prefix = text.substring(0, text.indexOf(BOOK_TITLE));
// Get the text after the marker...
text = text.substring(text.indexOf(BOOK_TITLE) + BOOK_TITLE.length());
// If there is text before the marker, append it to the call out node
if (prefix.length() > 0) {
Text textNode = doc.createTextNode(prefix);
callOut.appendChild(textNode);
}
// Append the book title node...
Element bookTitle = doc.createElement("BookTitle");
bookTitle.setTextContent(BOOK_TITLE);
callOut.appendChild(bookTitle);
}
// If there is any text remaining, append it to the call out node...
if (text.length() > 0) {
Text textNode = doc.createTextNode(text);
callOut.appendChild(textNode);
}
} else {
// No marker, append the text to the call out node..
Text textNode = doc.createTextNode(text);
callOut.appendChild(textNode);
}
// This will dump the result for you to test....
root.appendChild(callOut);
ByteArrayOutputStream baos = null;
OutputStreamWriter osw = null;
try {
baos = new ByteArrayOutputStream();
osw = new OutputStreamWriter(baos);
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty(OutputKeys.METHOD, "xml");
tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource domSource = new DOMSource(doc);
StreamResult sr = new StreamResult(osw);
tf.transform(domSource, sr);
osw.flush();
baos.flush();
System.out.println(new String(baos.toByteArray()));
} finally {
try {
baos.close();
} catch (Exception exp) {
}
}
} catch (IOException | TransformerException | ParserConfigurationException ex) {
ex.printStackTrace();
}
}
}

People will have different approaches to dealing with XML manipulations. The variety of answers to this question is proof enough of this. While using regex and raw text manipulation might be good for one off fixes and hacks if you want a good and maintainable solution you should use an XML API.
My example below does what is asked, however it should be noted that I didn't check for any pathological inputs like ("" as the search string) or deal with XML namespaces. Those things can be added easily enough.
See comments in the code for description of how it works.
Input (test.xml):
<Callouts>
<Callout>Save the User Guide.</Callout>
</Callouts>
Program
package com.stackoverflow._18774666;
import java.net.URL;
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.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class InsertElementInTextNode {
/**
* Replace text content of child text nodes of a parent element that
* matches a search string. The text is replace by an element named with the
* given name and has it's text content set equal to the search string.
*
* #param parent
* The element to search child text nodes of.
* #param elementName
* The name of the element to insert.
* #param text
* The text to replace with an element with same text content.
*/
public static void replaceTextWithElement(Element parent, String elementName, String text){
NodeList children = parent.getChildNodes();
Text cursor;
Element insertedElement;
int index;
/* Iterate children of the given element. */
for(int i = 0; i < children.getLength(); i++ ){
/* Check if this child is a text node. Ignore otherwise. */
if(children.item(i) instanceof Text){
cursor = (Text) children.item(i);
/* If the entire text node is equal to the search string,
* then we can replace it directly. Else we have split it.*/
if(text.equals(cursor.getData())){
/* Replace the text node with an element */
insertedElement = parent.getOwnerDocument().createElement(elementName);
insertedElement.setTextContent(text);
parent.replaceChild(insertedElement, cursor);
} else {
/* Check to see if the search string exists in this text node. Ignore otherwise.*/
index = cursor.getData().indexOf(text);
if(index != -1){
/* Replace the matched substring with an empty string.*/
cursor.replaceData(index, text.length(), "");
/* Create element to be inserted, and set the text content. */
insertedElement = parent.getOwnerDocument().createElement(elementName);
insertedElement.setTextContent(text);
/* Split the text node and insert the element in the middle. */
parent.insertBefore(insertedElement, cursor.splitText(index));
}
}
}
}
}
public static void main(String[] args) throws Exception {
/* Location of our XML document. */
URL xmlSource = InsertElementInTextNode.class.getResource("test.xml");
/* Parse with DOM in to a Document */
Document xmlDoc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(xmlSource.openStream());
/* Find our interesting elements. */
NodeList nodes = xmlDoc.getElementsByTagName("Callout");
/* Iterate through our interesting elements and check their content.*/
Element cursor;
for(int i = 0; i < nodes.getLength(); i++ ){
if(nodes.item(i) instanceof Element){
cursor = (Element) nodes.item(i);
replaceTextWithElement(cursor, "BookTitle", "User Guide");
}
}
/* Setup to output result. */
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
/* Printing result to stdout. */
transformer.transform(new DOMSource(xmlDoc),
new StreamResult(System.out));
}
}
Output (stdout):
<Callouts>
<Callout>Save the <BookTitle>User Guide</BookTitle>.</Callout>
</Callouts>

first get the user input and compare it to user guide, if it's true then surround it with title.
String UserInput = null;
UserInput = #getUserType.toString();
if(UserInput.equals("User Guide")){
UserInput = "<BookTitle>"+UserInput+"<BookTitle>";
}else{
//do things if it's false not User Guide
}

public static void main(String[] args) {
String str = "This is my User Guide dude";
boolean bTest = str.contains("User Guide");
if (bTest) {
int index1 = str.indexOf("User Guide");
String sub = str.substring(index1, index1 + 10);
sub = "<BookTitle>" + sub + "</BookTitle>";
String result = str.replace("User Guide", sub);
System.out.println(result);
}
}
OUTPUT:
This is my <BookTitle>User Guide</BookTitle> dude
I think this will point you in the right direction at least.

Related

String to xml elements in java

I'm working on a project in java but I need to create and xml from a list of Strings on this way:
1: "/data/user/firstname/John"
2: "/data/user/middlename/F"
3: "/data/user/lastname/Thomas"
and the expected result should be this one:
<data>
<user>
<firstname>John</firstname>
<middlename>F</middlename>
<lastname>Thomas</lastname>
</user>
<data>
does anyone know if it possible in java? Thank you!
Working example with plain Java, without frameworks:
package test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws ParserConfigurationException, TransformerException {
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
String a = "/data/user/firstname/John";
String b = "/data/user/middlename/F";
String c = "/data/user/lastname/Thomas";
// Create arrays from string and trim first empty space before first '/'
String [] arrayA = Arrays.copyOfRange(a.split("/"), 1, a.split("/").length);
String [] arrayB = Arrays.copyOfRange(b.split("/"), 1, b.split("/").length);
String [] arrayC = Arrays.copyOfRange(c.split("/"), 1, c.split("/").length);
Element parent = null;
for (int i = 0; i < arrayA.length; i++) {
// Append text to child nodes, do it at very end
if (i == arrayA.length - 1) {
Element element1 = (Element) document.getElementsByTagName(arrayA[i - 1]).item(0);
element1.appendChild(document.createTextNode(arrayA[i]));
Element element2 = (Element) document.getElementsByTagName(arrayB[i - 1]).item(0);
element2.appendChild(document.createTextNode(arrayB[i]));
Element element3 = (Element) document.getElementsByTagName(arrayC[i - 1]).item(0);
element3.appendChild(document.createTextNode(arrayC[i]));
break;
}
// if names are same, appending only one of them
if ((arrayA[i].equals(arrayB[i])) && (arrayA[i].equals(arrayC[i]))) {
System.out.println("true");
// create root node
if (i == 0) {
Element element = document.createElement(arrayA[i]);
document.appendChild(element);
parent = element;
System.out.println(document.toString());
} else {
Element element = document.createElement(arrayA[i]);
parent.appendChild(element);
parent = element;
System.out.println(document.toString());
}
// if node names at same levels are different, add all of them
} else {
System.out.println("false");
Element element1 = document.createElement(arrayA[i]);
Element element2 = document.createElement(arrayB[i]);
Element element3 = document.createElement(arrayC[i]);
parent.appendChild(element1);
parent.appendChild(element2);
parent.appendChild(element3);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult(new File("result.xml"));
transformer.transform(domSource, streamResult);
}
}
Output of this program:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><data><user><firstname>John</firstname><middlename>F</middlename><lastname>Thomas</lastname></user></data>
Or, write it to file, then, to last lines need to be:
StreamResult streamResult = new StreamResult(new File("result.xml"));
transformer.transform(domSource, streamResult);

Create XML file based on user input

Extreme Java newb...I am trying to create a program that will take user input and build an XML file based on input from the user. This file is used by a contact center platform to identify retail locations based on caller ID. The XML structure looks like this:
<StoreList>
<Store str_callingnumber="1234567890">
<Number>Store1000</Number>
<Street>123 USA BLVD</Street>
<City>Nashville, TN 37211</City>
<WUGID>1234</WUGID>
</Store>
</StoreList>
I want to prompt the user to enter the phone number, store number, street, city, and WUGID, but keep getting an error about cannot convert String to Node. All of the other information I see on here is about parsing an existing XML file or creating one with DOM...but I haven't found any hints on creating one based on user input. Here is my code thus far...
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
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.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.File;
import java.util.Scanner;
public class CreateXmlFileDemo {
public static void main(String argv[]) {
Scanner sc = new Scanner(System.in);
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
// root element
Element rootElement = doc.createElement("StoreList");
doc.appendChild(rootElement);
// store element
Element store = doc.createElement("Store");
rootElement.appendChild(store);
// setting str_calling number attribute to store element
System.out.println("Enter the store phone number:");
String phone = sc.next();
Attr attr = doc.createAttribute("str_callingnumber");
attr.setValue(phone);
store.setAttributeNode(attr);
// store number element
Element storenumber = doc.createElement("Number");
System.out.println("Enter the store number:");
var number = sc.next();
store.appendChild(number);
//street address element
Element street = doc.createElement("Street");
System.out.println("Enter the street address:");
String address = sc.next();
street.appendChild(address);
Element zip = doc.createElement("City");
System.out.println("Enter the city, state, and ZIP code:");
String city = sc.next();
zip.appendChild(city);
Element wug = doc.createElement("WUGID");
System.out.println("Enter the WUGID:");
String wugid = sc.next();
wug.appendChild(wugid);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("C:\\cars.xml"));
transformer.transform(source, result);
// Output to console for testing
StreamResult consoleResult = new StreamResult(System.out);
transformer.transform(source, consoleResult);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thank you anyone/everyone for taking the time to help me understand.
You seemed to have the right idea to start with, but got off track somewhere.
Basically, you're attempting to append a String value to a parent Node, but Node only accepts other Nodes as it children.
Instead, you need to apply the String value to the textContent of the Element you've already created and append the Element to the parent Node
Element storenumber = doc.createElement("Number");
System.out.println("Enter the store number:");
String number = sc.next();
//var number = sc.next();
//store.appendChild(number);
storenumber.setTextContent(number);
store.appendChild(storenumber);
Wash, rinse and repeat...

Having trouble formatting multiple nodes from a text to XML conversion in Java

I have a Java program which converts text files to XML. I need the following format:
<app:defaults>
<app:schedules>
<app:run>
<app:schedule>schedule frequency value</app:schedule>
</app:run>
</app:schedules>
<app:rununit>
<app:agent>agent hostname value</app:agent>
</app:rununit>
</app:defaults>
The ending "/app:schedules" tag is not appending in the correct place
after the "/app:run" tag. The program is instead generating the following (which is not correct):
<app:defaults>
<app:schedules>
<app:run>
<app:schedule>schedule frequency value</app:schedule>
</app:run>
<app:rununit>
<app:agent>agent hostname value</app:agent>
</app:rununit>
</app:schedules>
</app:defaults>
The method in the java program is as follows: for this example i expilicitly added the text to each node to show what the data should be. - this method takes String args otherwise from the input text file.
public static void main(String[] args) {
String infile = args[0];
String outxml = args[1];
BufferedReader in;
StreamResult out;
DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder icBuilder;
try {
in = new BufferedReader(new FileReader(infile));
out = new StreamResult(outxml);
icBuilder = icFactory.newDocumentBuilder();
Document doc = icBuilder.newDocument();
Element mainRootElement = doc.createElementNS ("http://dto.cybermation.com/application", "app:appl");
mainRootElement.setAttribute("name", "TESTSHEDULE");
doc.appendChild(mainRootElement);
...
private static Node processTagElements3(Document doc, String "app:defaults") {
Element node1 = doc.createElement("app:schedules");
Element node2 = doc.createElement("app:run");
Element node3 = doc.createElement("app:schedule");
Element node4 = doc.createElement("app:rununit");
Element node5 = doc.createElement("app:agent");
node1.appendChild(node2);
node2.appendChild(node3);
node3.appendChild(doc.createTextNode("schedule frequency value"));
node1.appendChild(node4);
node4.appendChild(node5);
node5.appendChild(doc.createTextNode("agent hostname value"));
return node1;
}
I've tested this using different appenchild parameters between these nodes but ran up against a brick wall with formatiing this output. Any suggestions, advice on the best way to organize the node tag insertions is really appreciated. There could be somthing simple I am missing.
Note: I'm not an expert in for XML parsing in Java.
Just trying to stitch some example codes I got in my machine and see if that solves your problem. So here it is.
Example code:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringReader;
import java.io.StringWriter;\
public class test {
public static void main(String[] args) throws Exception {
String xml = "<app:defaults>\n" +
" <app:schedules>\n" +
" <app:run>\n" +
" <app:schedule>schedule frequency value</app:schedule>\n" +
" </app:run>\n" +
" </app:schedules>\n" +
" <app:rununit>\n" +
" <app:agent>agent hostname value</app:agent>\n" +
" </app:rununit> \n" +
" </app:defaults>";
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new InputSource(new StringReader(xml)));
NodeList errNodes = doc.getElementsByTagName("error");
if (errNodes.getLength() > 0) {
Element err = (Element)errNodes.item(0);
System.out.println(err.getElementsByTagName("errorMessage")
.item(0).getTextContent());
} else {
// success
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
System.out.println(writer.toString());
}
}
Output:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<app:defaults>
<app:schedules>
<app:run>
<app:schedule>schedule frequency value</app:schedule>
</app:run>
</app:schedules>
<app:rununit>
<app:agent>agent hostname value</app:agent>
</app:rununit>
</app:defaults>
This code seems to be working as what you will expecting it to be. Give it a try and let me know whether the solution is okay.
I think the idea here is to use pre-baked Java APIs than writing our own parser. Because these APIs are generally more reliable since many others would be using it daily.
Things would be way easier if you had named your nodes with meaningful names (let's say runNode, etc), don't you think?
That being said, this is probably what you want:
Element defaultNode = doc.createElement("app:default");
Element schedulesNode = doc.createElement("app:schedules");
Element runNode = doc.createElement("app:run");
Element scheduleNode = doc.createElement("app:schedule");
Element rununitNode = doc.createElement("app:rununit");
Element agentNode = doc.createElement("app:agent");
defaultNode.appendChild(schedulesNode);
schedulesNode.appendChild(runNode);
runNode.appendChild(scheduleNode);
scheduleNode.appendChild(doc.createTextNode("schedule frequency value"));
defaultNode.appendChild(rununitNode);
rununitNode.appendChild(agentNode);
agentNode.appendChild(doc.createTextNode("agent hostname value"));
Note the defaultNode used.
Thanks all!
I decided to modify the script to accept file input as my arg - this works fine now and is a simpler solution:
public class test2 {
public static void main(String[] args) throws Exception {
File file = new File(args[0]);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try{
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream fis = new FileInputStream(file);
InputSource is = new InputSource(fis);
Document doc = builder.parse(is);
NodeList errNodes = doc.getElementsByTagName("error");
if (errNodes.getLength() > 0) {
Element err = (Element)errNodes.item(0);
System.out.println(err.getElementsByTagName("errorMessage").item(0).getTextContent());
} else {
// success
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
System.out.println(writer.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

DOM parser in java not encoding quotes in UTF-8

I am trying to use the code available from this tutorial :http://www.mkyong.com/java/how-to-create-xml-file-in-java-dom/
I've pasted the code below as well, the problem it seems to encode all the predef characters <,> and & etc. but not single or double quotes (" and '). I'd really appreciate a fix. Also the code below has an edit to make the resultant xml appear properly formatted
More specifically:
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class WriteXMLFile {
public static void main(String argv[]) {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// root elements
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("company");
doc.appendChild(rootElement);
// staff elements
Element staff = doc.createElement("Staff");
rootElement.appendChild(staff);
// set attribute to staff element
Attr attr = doc.createAttribute("id");
attr.setValue("1");
staff.setAttributeNode(attr);
// shorten way
// staff.setAttribute("id", "1");
// firstname elements
Element firstname = doc.createElement("firstname");
firstname.appendChild(doc.createTextNode("yong"));
staff.appendChild(firstname);
// lastname elements
Element lastname = doc.createElement("lastname");
lastname.appendChild(doc.createTextNode("mook kim"));
staff.appendChild(lastname);
// nickname elements
Element nickname = doc.createElement("nickname");
nickname.appendChild(doc.createTextNode("mkyong"));
staff.appendChild(nickname);
// salary elements
Element salary = doc.createElement("salary");
salary.appendChild(doc.createTextNode("100000"));
staff.appendChild(salary);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("C:\\file.xml"));
// Output to console for testing
// StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
System.out.println("File saved!");
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
}
}
}
I think your code works fine. Put a double quote in an attribute value and see what happens.
Read section 2.4 of the XML specification. Production 14 of the grammar
[14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
tells you that character data can be any (valid XML) character except '<' and '&' (or the ']]>' sequence). It is not strictly necessary to escape '>', although recommended.

XML Node to String in Java

I came across this piece of Java function to convert an XML node to a Java String representation:
private String nodeToString(Node node) {
StringWriter sw = new StringWriter();
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
} catch (TransformerException te) {
System.out.println("nodeToString Transformer Exception");
}
return sw.toString();
}
It looks straightforward in that it wants the output string doesn't have any XML declaration and it must contain indentation.
But I wonder how the actual output should be, suppose I have an XML node:
<p><media type="audio" id="au008093" rights="wbowned">
<title>Bee buzz</title>
</media>Most other kinds of bees live alone instead of in a colony. These bees make
tunnels in wood or in the ground. The queen makes her own nest.</p>
Could I assume the resulting String after applying the above transformation is:
"media type="audio" id="au008093" rights="wbowned" title Bee buzz title /media"
I want to test it myself, but I have no idea on how to represent this XML node in the way this function actually wants.
I am bit confused, and thanks in advance for the generous help.
All important has already been said. I tried to compile the following code.
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class Test {
public static void main(String[] args) throws Exception {
String s =
"<p>" +
" <media type=\"audio\" id=\"au008093\" rights=\"wbowned\">" +
" <title>Bee buzz</title>" +
" " +
" Most other kinds of bees live alone instead of in a colony." +
" These bees make tunnels in wood or in the ground." +
" The queen makes her own nest." +
"</p>";
InputStream is = new ByteArrayInputStream(s.getBytes());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document d = db.parse(is);
Node rootElement = d.getDocumentElement();
System.out.println(nodeToString(rootElement));
}
private static String nodeToString(Node node) {
StringWriter sw = new StringWriter();
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
} catch (TransformerException te) {
System.out.println("nodeToString Transformer Exception");
}
return sw.toString();
}
}
And it produced the following output:
<p> <media id="au008093" rights="wbowned" type="audio"> <title>Bee buzz</title> </media> Most other kinds of bees live alone instead of in a colony. These bees make tunnels in wood or in the ground. The queen makes her own nest.</p>
You can further tweak it by yourself. Good luck!
You have an XML respesentation in a DOM tree.
For example you have opened an XML file and you have passed it in the DOM parser.
As a result a DOM tree in memory with your XML is created.
Now you can only access the XML info via traversal of the DOM tree.
If you need though, a String representation of the XML info of the DOM tree you use a transformation.
This happens since it is not possible to get the String representation directly from a DOM tree.
So if for example as Node node you pass in nodeToString is the root element of the XML doc then the result is a String containing the original XML data.
The tags will still be there. I.e. you will have a valid XML representation. Only this time will be in a String variable.
For example:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
Document xmlDoc = parser.parse(file);//file has the xml
String xml = nodeToString(xmlDoc.getDocumentElement());//pass in the root
//xml has the xml info. E.g no xml declaration. Add it
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> + xml;//bad to append this way...
System.out.println("XML is:"+xml);
DISCLAIMER: Did not even attempt to compile code. Hopefully you understand what you have to do

Categories