开发者

How to update XML using XPath and Java

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&g开发者_如何学运维t;
    <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.


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


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")));


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.


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");


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.


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();


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;
}


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");
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜