You can use the JAXB Binder for this use case:
Input.xml
<?xml version="1.0" encoding="UTF-8"?> <customer> <UNMAPPED_ELEMENT_1/> <name>Jane Doe</name> <address> <UNMAPPED_ELEMENT_2/> <street>1 A Street</street> <UNMAPPED_ELEMENT_3/> <city>Any Town</city> </address> <UNMAPPED_ELEMENT_4/> <phone-number type="home">555-HOME</phone-number> <phone-number type="cell">555-CELL</phone-number> <UNMAPPED_ELEMENT_5/> </customer>
Demo
import java.io.File; import javax.xml.bind.*; 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 BinderDemo { public static void main(String[] args) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); File xml = new File("input.xml"); Document document = db.parse(xml); JAXBContext jc = JAXBContext.newInstance(Customer.class); Binder<Node> binder = jc.createBinder(); Customer customer = (Customer) binder.unmarshal(document); customer.getAddress().setStreet("2 NEW STREET"); PhoneNumber workPhone = new PhoneNumber(); workPhone.setType("work"); workPhone.setValue("555-WORK"); customer.getPhoneNumbers().add(workPhone); binder.updateXML(customer); TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = tf.newTransformer(); t.transform(new DOMSource(document), new StreamResult(System.out)); } }
Exit
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <customer> <UNMAPPED_ELEMENT_1/> <name>Jane Doe</name> <address> <UNMAPPED_ELEMENT_2/> <street>2 NEW STREET</street> <UNMAPPED_ELEMENT_3/> <city>Any Town</city> </address> <UNMAPPED_ELEMENT_4/> <phone-number type="home">555-HOME</phone-number> <phone-number type="cell">555-CELL</phone-number> <phone-number type="work">555-WORK</phone-number> <UNMAPPED_ELEMENT_5/> </customer>
Additional Information
source share