I am writing some data to an XML file.
Here is the code:
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();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("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();
}
}
This code writes the XML data to the "file.xml". If I already have a "file.xml" file, what is the best way to append the XML data to the file? Will I need to rewrite the whole above code, or is it easy to adapt the code?
Yes - you're dealing with DOM, so you have to have the whole file in memory. Alternative is StAX.
StreamResult result = new StreamResult(new File("file.xml"));
Check this line.
Replace the above line with this.
StreamResult result = new StreamResult(new FileOutputStream("file.xml", true));
By default the second parameter is false.
True means it will append to file, false means it will overwrite it.
Related
I am creating a simple java function to update/re-write the value of an xml file.
I am able to pick the XML file from the system resource, after updating the file and re-writing, the value of the node never gets changes.
Here are my snippets:
String filePath = ABS_PATH + File.separator + "fields.xml";
File xmlFile = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
//update Element value
updateElementValue(doc);
//write the updated document to file or console
doc.getDocumentElement().normalize();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(ABS_PATH
+ File.separator + "fields.xml")); // updating/re-writing the same file
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
System.out.println("XML file updated successfully");
} catch (SAXException | ParserConfigurationException | IOException | TransformerException e1) {
e1.printStackTrace();
}
//method to show the update element value
private static void updateElementValue(Document doc) {
NodeList employees = doc.getElementsByTagName("NO");
Element emp = null;
//loop for each
for (int i = 0; i < employees.getLength(); i++) {
emp = (Element)employees.item(i);
Node name = emp.getElementsByTagName("String").item(0).getFirstChild();
name.setNodeValue(name.getNodeValue().toUpperCase());
}
}
sample of the xml file
<Document xmlns="http://hello.com/schema/public/services/platform" Id="1">
<Fields>
<Field FieldName="NO">
<String>Demo</String>
</Field>
<Field FieldName="TYPE">
<String>Zada</String>
</Field>
</Fields>
who is motivated enough to assist
You have the following statement:
NodeList employees = doc.getElementsByTagName("NO");
It will return an empty list, since your XML does not have any nodes with "NO" as a tag.
<Field FieldName="NO">
Statements inside your loop iterating through the list will never be executed. You node will not be updated.
Your elements with tag Field have attribute FieldName. One of them has attribute value of "NO". So you need to find it.
See if How to get specific XML elements with specific attribute value? gives you enough guidance.
You can do it with a loop as well.
NodeList employees = doc.getElementsByTagName("Field");
for (int i = 0; i < employees.getLength(); i++) {
emp = (Element)employees.item(i);
if ("NO".equals(emp.item(i).getAttribute("FieldName"))) {
// do your stuff
}
}
The above is not tested.
I have a trouble in finding info about creating a multi level tags in xml file
for example i want next structure
<UserCards>
<UserCard userCardId="171">
<userName>somename</userName>
<userSurname>somesurname</userSurname>
<userAge>24</userAge>
<userAdress>someadress</userAdress>
<userPhone>223334455</userPhone>
<CurrentBooks>
<booName>someBookName</bookName>
</CurrentBooks>
</UserCard>
</UserCards>
I can create simple one level xml but how can I add new one?
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBulder = docFactory.newDocumentBuilder();
//root mainElement
Document doc = docBulder.newDocument();
Element rootElement = doc.createElement("UserCards");
doc.appendChild(rootElement);
//root Book
Element UserCard = doc.createElement("UserCard");
rootElement.appendChild(UserCard);
...
...
//write in a XMLFile
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("Test/UserCards.xml"));
seems to me like you answered it yourself....
You can append elements to any element, not just the root.
You create all Elements by calling doc.createElement("name")
and append to the parent element of your choice:
Elmenet userName = doc.createElement("userName");
Text userNameText = doc.createTextNode("somename");
userName.appendChild(userNameText);
UserCard.appendChild(userName);
Try this
Element rootElement = doc.createElement("UserCards");
doc.appendChild(rootElement);
//root Book
Element UserCard = doc.createElement("UserCard");
UserCard.setAttribute("userCardId" , "171");
Element userSurname = doc.createElement("userSurname");
UserCard.appendChild(userSurname);
Element userAge = doc.createElement("userAge");
UserCard.appendChild(userAge);
Element userAdress = doc.createElement("userAdress");
UserCard.appendChild(userAdress);
Element userPhone = doc.createElement("userPhone");
UserCard.appendChild(userPhone);
Element CurrentBooks = doc.createElement("CurrentBooks");
Element booKName = doc.createElement("booKName");
CurrentBooks.appendChild(booKName);
UserCard.appendChild(CurrentBooks);
rootElement.appendChild(UserCard);
I am creating target XML by copying source XML content. I am doing copy at node level.
Source XML has content with escape character which gets converted [$quot; to " etc...] while I create my target XML
Is there any way to retain original XML content.
Appreciate any help on this.
copyXmlFile("Workflow", "./Source.xml", "./Destination.xml");
private static void copyXmlFile(String xmlType, String objectSourceFile, String outfile) throws TransformerException {
//Get the DOM Builder Factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//Get the DOM Builder
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
//document contains the complete XML as a Tree.
try {
File xmlFileContent = new File(objectSourceFile);
Document document = builder.parse(new FileInputStream(xmlFileContent));
// root elements
Document documentOut = builder.newDocument();
Element rootElementOut = documentOut.createElement(xmlType);
rootElementOut.setAttribute("xmlns", "http://soap.sforce.com/2006/04/metadata");
documentOut.appendChild(rootElementOut);
NodeList nodeList = document.getDocumentElement().getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element) {
//Node copiedNode = documentOut.importNode(node, true);
//rootElementOut.appendChild(copiedNode);
rootElementOut.appendChild(documentOut.adoptNode(node.cloneNode(true)));
}
}
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(documentOut);
//StreamResult result = new StreamResult(new File(outfile));
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//transformer.setOutputProperty(OutputKeys.METHOD, "xml");
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(source, result);
System.out.println("Escaped XML String in Java: " + writer.toString());
} catch (SAXException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
I have an object which holds data of a person. When a user clicks on the download button the xml needs to be created by (person.dataitems) and after that user should have an option to download the file (like save file or open file)
I have written the code below which creates a xml file when the button is clicked however the file remains empty. I would like to know how I can write data to this file and then download.
response.setHeader( "Content-Disposition", "attachment;filename="+patient.getGivenName()+".xml");
try {
StringWriter r = new StringWriter();
String ccdDoc = r.toString();
ccdDoc = ccdDoc.replaceAll("<", "<");
ccdDoc = ccdDoc.replaceAll(""", "\"");
byte[] res = ccdDoc.getBytes(Charset.forName("UTF-8"));
response.setCharacterEncoding("UTF-8");
response.getOutputStream().write(res);
response.flushBuffer();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thanks.
You have to write into your StringWriter:
import java.io.*;
public class StringWriterDemo {
public static void main(String[] args) {
String s = "Hello World";
// create a new writer
StringWriter sw = new StringWriter();
// write portions of strings
sw.write(s, 0, 4);
sw.write(s, 5, 6);
// write full string
sw.write(s);
// print result by converting to string
System.out.println("" + sw.toString());
}
}
Do not do:
String ccdDoc = r.toString();
It only creates a copy of the r string. Then you are modifying the copy, but not at all the content of the StringWriter.
Do:
r.write("some content");
and to access the string contained by the writer, do:
String a_string = r.toString();
response.getOutputStream().write(a_string);
EDIT :
OK, so what you are asking is not so far from what you have in the link you provided, excepted that you have to write into a StringWriter instead of into a File.
This can be achieved this way:
1) Do build an xml document:
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
staff.setAttribute("id", "1");
// firstname elements
Element firstname = doc.createElement("firstname");
firstname.appendChild(doc.createTextNode("yong"));
staff.appendChild(firstname);
:
:
// Then write the doc into a StringWriter
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with StringWriter object to save to string
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
// Finally, send the response
byte[] res = xmlString.getBytes(Charset.forName("UTF-8"));
response.setCharacterEncoding("UTF-8");
response.getOutputStream().write(res);
response.flushBuffer();
The point here is to do:
StreamResult result = new StreamResult(new StringWriter());
instead of:
StreamResult result = new StreamResult(new File("C:\\file.xml"));
You tell me if there is still something unclear in this.
it's worked
byte[] res = xmlString.getBytes(Charset.forName("UTF-8"));
response.setCharacterEncoding("UTF-8");
response.setHeader( "Content-Disposition", "attachment;filename=archivo.xml");
response.getOutputStream().write(res);
response.flushBuffer();
I am writing a Java application with a method to save data to XML.
Here is my code:
private void SaveToXML(String strCity, String strDate, String strforecast, String strminDegrees, String FileName)
{
try
{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("Weather");
doc.appendChild(rootElement);
Element weatherElement = doc.createElement(strCity);
rootElement.appendChild(weatherElement);
Element dateElement = doc.createElement("Date");
weatherElement.appendChild(dateElement);
Attr attr = doc.createAttribute("id");
attr.setValue(strDate);
dateElement.setAttributeNode(attr);
Element forecast = doc.createElement("forecast");
forecast.appendChild(doc.createTextNode(strforecast));
dateElement.appendChild(forecast);
Element mindegrees = doc.createElement("mindegrees");
mindegrees.appendChild(doc.createTextNode(strminDegrees));
dateElement.appendChild(mindegrees);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(FileName));
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
}
}
Method call:
SaveToXML("Auckland", "24-05-2013", "Fine", "10", "Test.xml");
Here is the output XML data:
<?xml version="1.0" encoding="UTF-8"?>
<Weather>
<Auckland>
<Date id="24-05-2013">
<forecast>Fine</forecast>
<mindegrees>10</mindegrees>
</Date>
</Auckland>
</Weather>
Can I please have some help to modify the code so that data is appended to the document in the correct element when the method is called.
E.g, If the method is called a second time with the City of Auckland, the weather details will be placed in the Auckland element. If a City is passed as a parameter that is not already in the document, a new element for that City will be created.
UPDATE2
This is my current code that performs an error:
private void SaveToXML(String strCity, String strDate, String strforecast, String strminDegrees, String FileName)
{
try
{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
//Document doc = docBuilder.newDocument();
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(FileName));
Element rootElement = doc.createElement("Weather");
doc.appendChild(rootElement);
NodeList weatherNodes = rootElement.getElementsByTagName(strCity);// do we already have node?
Element weatherElement;
if(weatherNodes.getLength() > 0){ // if so reuse
weatherElement = (Element) weatherNodes.item(0);
System.out.println("Found");
}else { // else create
weatherElement = doc.createElement(strCity);
rootElement.appendChild(weatherElement);
}
Element dateElement = doc.createElement("Date");
weatherElement.appendChild(dateElement);
Attr attr = doc.createAttribute("id");
attr.setValue(strDate);
dateElement.setAttributeNode(attr);
Element forecast = doc.createElement("forecast");
forecast.appendChild(doc.createTextNode(strforecast));
dateElement.appendChild(forecast);
Element mindegrees = doc.createElement("mindegrees");
mindegrees.appendChild(doc.createTextNode(strminDegrees));
dateElement.appendChild(mindegrees);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(FileName));
transformer.transform(source, result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
The above code generates this error at runtime:
[Fatal Error] Test.xml:1:177: The markup in the document following the root element must be well-formed.
org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.
UPDATE3
Here is the code that is working:
private void SaveToXML(String strCity, String strDate, String strforecast, String strminDegrees, String FileName)
{
try
{
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc;
File file = new File(FileName);
if (!file.exists()) {
doc = docBuilder.newDocument();
doc.appendChild(doc.createElement("Weather"));
} else {
doc = docBuilder.parse(new File(FileName));
}
Element rootElement = doc.getDocumentElement();
Element weatherElement;
NodeList weatherNodes = doc.getDocumentElement().getElementsByTagName(strCity);
if (weatherNodes.getLength() > 0) {
weatherElement = (Element) weatherNodes.item(0);
} else {
weatherElement = doc.createElement(strCity);
rootElement.appendChild(weatherElement);
}
Element dateElement = doc.createElement("Date");
weatherElement.appendChild(dateElement);
Attr attr = doc.createAttribute("id");
attr.setValue(strDate);
dateElement.setAttributeNode(attr);
Element forecast = doc.createElement("forecast");
forecast.appendChild(doc.createTextNode(strforecast));
dateElement.appendChild(forecast);
Element mindegrees = doc.createElement("mindegrees");
mindegrees.appendChild(doc.createTextNode(strminDegrees));
dateElement.appendChild(mindegrees);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(FileName));
transformer.transform(source, result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
To modify how you update the document structure for DOM,
modify
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("Weather");
doc.appendChild(rootElement);
Element weatherElement = doc.createElement(strCity);
rootElement.appendChild(weatherElement);
to
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("Weather");
doc.appendChild(rootElement);
NodeList weatherNodes = rootElement.getElementsByTagName(strCity);// do we already have node?
Element weatherElement;
if(weatherNodes.getLength() > 0){ // if so reuse
weatherElement = (Element) weatherNodes.item(0);
}else { // else create
weatherElement = doc.createElement(strCity);
rootElement.appendChild(weatherElement);
}
Be aware the DOM is really intended for small documents if this is going to get very large
you will need to look at something like STaX.
If XML file already exists you should parse it and update the city if it already exists or add otherwise. Then rewrite XML.
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc;
File file = new File(FileName);
if (!file.exists()) {
doc = docBuilder.newDocument();
doc.appendChild(doc.createElement("Weather"));
} else {
doc = docBuilder.parse(file);
}
Element rootElement = doc.getDocumentElement();
Element weatherElement = createWeatherElement(strCity, strDate, strforecast, strminDegrees, doc);
NodeList weatherNodes = doc.getDocumentElement().getElementsByTagName(strCity);
if (weatherNodes.getLength() > 0) {
rootElement.replaceChild(weatherElement, weatherNodes.item(0));
} else {
rootElement.appendChild(weatherElement);
}
Transformer transformer = transformerFactory.newTransformer();
...
private Element createWeatherElement(String strCity, String strDate, String strforecast, String strminDegrees, Document doc) {
Element rootElement = doc.getDocumentElement();
Element weatherElement = doc.createElement(strCity);
...
return weatherElement;
}