How to modify XML file in Java – (JDOM)
This tutorial shows how to use the JDOM to modify an XML file.
Table of contents
- 1. Download the JDOM 2.x
- 2. The XML file, before and after
- 3. Modify XML file
- 4. Find and remove XML elements
- 5. Download Source Code
- 6. References
P.S Tested with JDOM 2.0.6
Note
We need to understand how to JDOM parse XML and write XML, in order to modify the XML documents.
1. Download the JDOM 2.x
Maven for JDOM.
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
2. The XML file, before and after
2.1 The original XML file.
<?xml version="1.0" encoding="utf-8"?>
<company>
<staff id="1001">
<name>mkyong</name>
<role>support</role>
<salary currency="USD">5000</salary>
<!-- for special characters like < &, need CDATA -->
<bio><![CDATA[HTML tag <code>testing</code>]]></bio>
</staff>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
<salary currency="EUR">8000</salary>
<bio><![CDATA[a & b]]></bio>
</staff>
</company>
2.2 See below JDOM example to modify the above XML, add, remove and update the elements, attribute, comments, CDATA, etc.
For staff, id is 1001
- Remove XML element
role
- Update XML element
salary
, update attribute to MYR
For staff, id is 1002
- Remove xml element
name
- Add a new xml element
address
and CDATA content - Update xml element
salary
to 2000 - Remove the xml element CDATA
Also, add a new XML child node, staff
, and remove all the XML comments.
The below is the modified XML Output.
<?xml version="1.0" encoding="UTF-8"?>
<company>
<staff id="1001">
<name>mkyong</name>
<salary currency="MYR">5000</salary>
<bio><![CDATA[HTML tag <code>testing</code>]]></bio>
</staff>
<staff id="1002">
<role>admin</role>
<salary currency="EUR">2000</salary>
<bio>a & b & c</bio>
<address><![CDATA[123 & abc]]></address>
</staff>
<staff id="1003" />
</company>
3. Modify XML file
The below example uses JDOM to parse the above XML file, modify the content and write it to a file.
Read the code comments for self-explanatory.
package com.mkyong.xml.jdom;
import org.jdom2.CDATA;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import javax.xml.XMLConstants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class ModifyXmlJDom {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) throws JDOMException, IOException {
SAXBuilder sax = new SAXBuilder();
// https://rules.sonarsource.com/java/RSPEC-2755
// prevent xxe
sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Document doc = sax.build(new File(FILENAME));
Element rootNode = doc.getRootElement();
List<Element> listChildrenNode = rootNode.getChildren("staff");
// staff = 2
System.out.println("No of child nodes: " + listChildrenNode.size());
// loop the elements
for (Element staff : listChildrenNode) {
String id = staff.getAttribute("id").getValue();
// if staff id is 1001
if ("1001".equals(id.trim())) {
// remove element role
staff.removeChild("role");
// update xml element `salary`, update attribute to MYR
staff.getChild("salary").setAttribute("currency", "MYR");
}
// if staff id is 1002
if ("1002".equals(id.trim())) {
// remove xml element `name`
staff.removeChild("name");
// add a new xml element `address` and CDATA content
staff.addContent(new Element("address")
.addContent(new CDATA("123 & abc")));
// update xml element `salary` to 2000
staff.getChild("salary").setText("2000");
// remove the xml element CDATA
staff.getChild("bio").setText("a & b & c"); // now the & will escape automatically
}
// Java 8 to remove all XML comments
staff.getContent().removeIf(
content -> content.getCType() == Content.CType.Comment);
// remove the XML comments via iterator
/*ListIterator<Content> iter = staff.getContent().listIterator();
while (iter.hasNext()) {
Content content = iter.next();
if (content.getCType() == Content.CType.Comment) {
iter.remove();
}
}*/
}
// add a new XML child node, staff id 1003
rootNode.addContent(new Element("staff").setAttribute("id", "1003"));
// print to console for testing
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
// write to console
// xmlOutput.output(doc, System.out);
// write to a file
try (FileOutputStream output =
new FileOutputStream("c:\\test\\staff-update.xml")) {
xmlOutput.output(doc, output);
}
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<company>
<staff id="1001">
<name>mkyong</name>
<salary currency="MYR">5000</salary>
<bio><![CDATA[HTML tag <code>testing</code>]]></bio>
</staff>
<staff id="1002">
<role>admin</role>
<salary currency="EUR">2000</salary>
<bio>a & b & c</bio>
<address><![CDATA[123 & abc]]></address>
</staff>
<staff id="1003" />
</company>
4. Find and remove XML elements
If an XML element name
equals mkyong
, remove its data, and the entire staff
elements.
package com.mkyong.xml.jdom;
import org.jdom2.CDATA;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import javax.xml.XMLConstants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class ModifyXmlJDom4 {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) throws JDOMException, IOException {
SAXBuilder sax = new SAXBuilder();
// https://rules.sonarsource.com/java/RSPEC-2755
// prevent xxe
sax.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
sax.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Document doc = sax.build(new File(FILENAME));
Element rootNode = doc.getRootElement();
List<Element> listChildrenNode = rootNode.getChildren("staff");
// loop the elements
for (Element staff : listChildrenNode) {
// if name = mkyong, remove the staff node
if ("mkyong".equals(staff.getChildText("name"))) {
rootNode.removeContent(staff);
}
}
// print to console for testing
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
// write to console
xmlOutput.output(doc, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<company>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
<salary currency="EUR">8000</salary>
<bio><![CDATA[a & b]]></bio>
</staff>
</company>
Note
More JDOM2 examples – JDOM2 A Primer
5. Download Source Code
$ git clone https://github.com/mkyong/core-java
$ cd java-xml
$ cd src/main/java/com/mkyong/xml/jdom/
removing a single field is trival.
how does one do the more common practice of identifying a record by a value (eg staff member: mkyong) and then remove ALL of mkyong’s data from his mkyong record, smoothly and safely?
Refer to the above example 4
https://mkyong.com/java/how-to-modify-xml-file-in-java-jdom/#find-and-remove-xml-elements
for (Element staff : listChildrenNode) {
// if name = mkyong, remove the staff node
if ("mkyong".equals(staff.getChildText("name"))) {
rootNode.removeContent(staff);
}
}