6

Here is my Code so far:

// locate the node(s)
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList)xpath.evaluate("//root[text()='input[1]']", doc, XPathConstants.NODESET);

// make the change
for (int idx = 0; idx < nodes.getLength(); idx++) {
    nodes.item(idx).setTextContent(input[3]);
}

// save the result
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new DOMSource(doc), new StreamResult(new File(outputFile)));

Input[1] is what I am looking for in the XML, and input [3] is what it is being replaced with.

Here is the XML:

<root> 
    <accounts> 
        <account name="Bill Gates">
            <position>CEO</position> 
            <phoneNumber>123-485-1854</phoneNumber>
            <notes>Runs the company</notes> 
        </account> 
        <account name="Service Account"/> 
        <account name="Burt Mackland"> 
            <position>CFO</position> 
            <phoneNumber>345-415-4813</phoneNumber> 
            <notes>Great CFO</notes> </account> 
        <account name="Joe Smith"> 
            <position>Accountant</position>
            <reportsTo>Burt Mackland</reportsTo>
            <phoneNumber>135-118-7815</phoneNumber> 
            <notes>Must have ID checked at all Gates</notes>
        </account> 
    </accounts> 
    <departments> 
        <deparment name="Finance"> 
            <employeeCount>2</employeeCount> 
        </deparment> 
        <department name="Human Resources"> 
            <employeeCount>0</employeeCount> 
        </department> 
        <department name="Executive"> 
            <employeeCount>2</employeeCount>
        </department> 
    </departments> 
</root>

The user may not know what is in the XML. So i cannot hardcode the Xpath in the code. Please any would be greatly appreciated!

1
  • Also would anyone happen to know how I can change the node value and attribute value partially? Meaning, given the search word "Gates" which can be found in two places, one that is a node value and one that is a attribute value. How would I change it so only the word Gates is replaced with the user input? Commented May 17, 2013 at 19:45

1 Answer 1

8

As you want to search for text in any element (not only <root>), change the XPath expression from

//root[text()='TEXT-TO-BE-FOUND']

To

//*[text()='TEXT-TO-BE-FOUND']

To find all attributes with the same value, you must use the following XPath expression:

//*/@*[.='TEXT-TO-BE-FOUND']

Also, as you can't hardcode, make TEXT-TO-BE-FOUND a variable. (Note: TEXT-TO-BE-FOUND must be escaped, it may not contain ' as it will affect the XPath expression.)

Working code below. It will replace all elements and all atributes with the input value:

import java.io.File;
import java.util.Scanner;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import org.w3c.dom.*;

public class XmlChange {

    public static void main(String argv[]) throws Exception {
        Scanner keyboard = new Scanner(System.in);
        System.out.print("Type like textToFind,textToReplace: "); // type, for example CEO,Chief Executive Officer
        String next = keyboard.nextLine();
        
        String[] input = next.split(",");
        
        String textToFind = input[0].replace("'", "\\'"); //"CEO";
        String textToReplace = input[1].replace("'", "\\'"); // "Chief Executive Officer";
        String filepath = "root.xml";
        String fileToBeSaved = "root2.xml";

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document doc = docBuilder.parse(filepath);

        XPath xpath = XPathFactory.newInstance().newXPath();
        // change ELEMENTS


        String xPathExpression = "//*[text()='" + textToFind + "']";
        NodeList nodes = (NodeList) xpath.evaluate(xPathExpression, doc, XPathConstants.NODESET);

        for (int idx = 0; idx < nodes.getLength(); idx++) {
            nodes.item(idx).setTextContent(textToReplace);
        }
        
        // change ATTRIBUTES
        String xPathExpressionAttr = "//*/@*[.='" + textToFind + "']";
        NodeList nodesAttr = (NodeList) xpath.evaluate(xPathExpressionAttr, doc, XPathConstants.NODESET);
        
        for(int i=0; i<nodesAttr.getLength(); i++) {
            nodesAttr.item(i).setTextContent(textToReplace);
        }
        System.out.println("Everything replaced.");

        // save xml file back
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new File(fileToBeSaved));
        transformer.transform(source, result);
    }
}
Sign up to request clarification or add additional context in comments.

9 Comments

Hmmm...that is a very good idea but for some reason having it as a variable doesn't seem to be working. I have the user input the text to Find and the text to be replaced so I can't hard code those either.
// locate the node(s) XPath xpath = XPathFactory.newInstance().newXPath(); NodeList nodes = (NodeList)xpath.evaluate(input[1], doc, XPathConstants.NODESET);
I have that, and I have the user input as: System.out.println("To modify a basic file Type:"); System.out.println("find, //*[text()='<Node Value>'], replace with, <Node Value>.");
For that code to work, input must be a String[], and the second item (that is, index 1), should be the xPath Expression. Where are you taking this user input from?
I also need to be able to look through the attribute values and replace them if necessary...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.