30

I have an XML document, and an XPath expression for that doc. I have to update the doc by using XPath at runtime.

How can I do this using Java?

The below is my xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<PersonList>
    <Person>
        <Name>Sonu Kapoor</Name>
        <Age>24</Age>
        <Gender>M</Gender>
        <PostalCode>54879</PostalCode>
    </Person>
    <Person>
        <Name>Jasmin</Name>
        <Age>28</Age>
        <Gender>F</Gender>
        <PostalCode>78745</PostalCode>
    </Person>
    <Person>
        <Name>Josef</Name>
        <Age>232</Age>
        <Gender>F</Gender>
        <PostalCode>53454</PostalCode>
    </Person>
</PersonList>

I have to change the values of name and age under //PersonList/Person[2]/Name.

Pops
  • 30,199
  • 37
  • 136
  • 151
samash
  • 757
  • 2
  • 15
  • 32

8 Answers8

33

Use setNodeValue. First, get a NodeList, for example:

myNodeList = (NodeList) xpath.compile("//MyXPath/text()")
           .evaluate(myXmlDoc, XPathConstants.NODESET);

Then set the value of e.g. the first node:

myNodeList.item(0).setNodeValue("Hi mom!");

More examples e.g. here.

As mentioned in two other answers here, as well as in your previous question: technically, XPath is not a way to "update" an XML document, but only to locate nodes within an XML document. But I presume the above is what you want.

EDIT: Responding to your comment... Are you asking how to write your DOM to an XML file after you've finished editing the DOM? If so, here are two examples of how to do it:

http://www.java2s.com/Code/Java/XML/WriteDOMout.htm

http://download.oracle.com/javaee/1.4/tutorial/doc/JAXPXSLT4.html

Community
  • 1
  • 1
Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
  • 1
    at this step i already done.but now how to set this node object into document.we can't use doc.appendChild(myNodeList.item(0));.because we i do not want to append the new node i want to just set the value of an element.For this ,Do we need to remove the older node and add the another node with updated values...???? – samash May 26 '11 at 11:53
  • Thanks. What if I need to change the node attribute? – Dejell Jul 21 '14 at 10:48
  • You can just use `XPathConstants.NODE` if you select one node and omit the index access `myNodeList.item(0)`, because evaluate will return a `Node` – René Link Nov 21 '18 at 15:50
7

You can delete the file and create a new one.

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
    new InputSource("data.xml"));

XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xpath.evaluate("//employee/name[text()='old']", doc,
    XPathConstants.NODESET);

for (int idx = 0; idx < nodes.getLength(); idx++) {
  nodes.item(idx).setTextContent("new value");
}

Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new DOMSource(doc), new StreamResult(new File("data_new.xml")));
Sorter
  • 9,704
  • 6
  • 64
  • 74
4

XPath is used to select parts of an XML document.It has no provision for updating. But since it returns DOM objects (Elements, if memory serves, or maybe Nodes) you can then use DOM methods for altering the document.

developer
  • 9,116
  • 29
  • 91
  • 150
3

XPath can be used to select nodes in a document, not for modification

You apply the xpath expression to your document and get an element (in your case). Once you have this Element, you can use the Element methods to change values (name and age in your case)


Starting from a NodeList it should work like that:

NodeList nodes = getNodeListFromXPathExpression();  // you know how
if (nodes.length == 0)
   return;  // empty nodelist, xpath didn't select anything

Node first = node.getItem(0);    // take the first from the list, your element

// this is a shortcut for your example:
//  first is the actual selected element (a node)
//  .getFirst() returns the first child node, the "text node" (="Jasmine", ="28")
//  .setNodeValue() replace the actual value of that text node with a new string
first.getFirstChild().setNodeValue("New Name or new age");
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
  • i can get Nodelist from xpath expression but after that how to modify with that...Can u please put a sample piece of code....I am not expert in XML....... – samash May 25 '11 at 12:21
3

Consider using XQuery Update instead of XPath. This allows you to write

replace value of node //PersonList/Person[2]/Name with "Anonymous"

This is much easier than using the Java DOM API.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Drawback of using XQuery: AFAIK there is no default XQuery implementation in "standard" JDK (up to v8) -> additional lib/dependency is required – Peti Jul 21 '15 at 10:39
  • Downloading a JAR file and adding it to the classpath is surely bread-and-butter for any Java programmer! – Michael Kay Jul 21 '15 at 10:57
1

I've created a small project for using XPATH to create/update XML: https://github.com/shenghai/xmodifier the code to change your xml is like:

Document document = readDocument("personList.xml");
XModifier modifier = new XModifier(document);
modifier.addModify("//PersonList/Person[2]/Name", "newName");
modifier.modify();
1

This is a super cool function where you can able to modify any tag value for any XML document using its xpath. You need to pass three arguments xml,xpathExpression and newValue and it returns the XML file as String with modified value.

If you want to pass XML as file, you need to change the function accordingly. But the logic will be same.

 public String updateXML(String xml, String xpathExpression, String newValue)
 {
    try {
        //Creating document builder
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document document = builder.parse(new org.xml.sax.InputSource(new StringReader(xml)));
      
        //Evaluating xpath expression using Element
        XPath xpath = XPathFactory.newInstance().newXPath();
        Element element = (Element)xpath.evaluate(xpathExpression, document, XPathConstants.NODE);
        
        //Setting value in the text
        element.setTextContent(value);

        //Transformation of document to xml
        StringWriter stringWriter = new StringWriter();
        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(new DOMSource(document), new StreamResult(stringWriter));

        xml = stringWriter.toString();
        } 
        catch (Exception e) 
        {
           e.printStackTrace();
        }
    return xml;
}
vkrams
  • 7,267
  • 17
  • 79
  • 129
  • `xpath.evaluate(xpathExpression, document, XPathConstants.NODE);` return an `org.w3c.dom.Node` but no `Element` – Ralph Jul 31 '21 at 18:38
  • org.w3c.dom.Node element = (Node) xpath.evaluate(xpathExpression, document, XPathConstants.NODE); element.setNodeValue(newValue); this worked for me – Srinivas Nangana Aug 24 '23 at 11:56
0

Here is the code to change the content with vtd-xml... vtd-xml is unique in that it is the only API that offers incremental update capability.

import com.ximpleware.*;
import java.io.*;

public class changeName {
    public  static  void main(String s[]) throws VTDException,java.io.UnsupportedEncodingException,java.io.IOException{
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("input.xml", false))
            return;
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        XMLModifier xm = new XMLModifier(vn);
        ap.selectXPath("//PersonList/Person[2]");
        int i=0;
        while((i=ap.evalXPath())!=-1){
            if (vn.toElement(VTDNav.FIRST_CHILD,"Name")){
                 int k=vn.getText();
                 if (i!=-1)
                    xm.updateToken(k, "Jonathan"); 
                 vn.toElement(VTDNav.PARENT);
            }
            if (vn.toElement(VTDNav.FIRST_CHILD,"Age")){
                 int k=vn.getText();
                 if (i!=-1)
                    xm.updateToken(k, "42"); 
                 vn.toElement(VTDNav.PARENT);
            }
        }
        xm.output("new.xml");
    }
}
vtd-xml-author
  • 3,319
  • 4
  • 22
  • 30