Read value from XML String using XPATH Java - java

I am looking to retrieve the value of Body element from XML. Though I've done the code right due to some reason I am getting NULL pointer exception.Any help is appreciated.
package com.company;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.io.StringBufferInputStream;
import java.io.StringReader;
public class Main {
public static void main(String[] args) {
String xmlDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Body>This is my content</Body>";
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(new InputSource(new StringReader(xmlDoc)));
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile("/Body");
Node node = (Node) expression.evaluate(document, XPathConstants.NODE);
System.out.println("Body: " + node.getAttributes().getNamedItem("Body").getNodeValue());
}
catch (ParserConfigurationException | SAXException | IOException | DOMException | XPathExpressionException exp)
{
exp.printStackTrace();
}
}
}

Try this :)
String xmlDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Body>This is my content</Body>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
String value = builder.parse(new InputSource(new ByteArrayInputStream(xmlDoc.getBytes())))
.getDocumentElement().getTextContent();
It returns value inside <Body> tag - "This is my content".

Use Node node = (Node) expression.evaluate(document, XPathConstants.NODE); System.out.println(node.getTextContent());. But obviously you don't need XPath and can do document.getDocumentElement().getTextContent() directly. Also note that for XPath use in general a namespace aware document builder is recommended.

Related

How to insert a new XML node within an existing Node using Java

I am trying to insert a new node within an exsting node for N number of times, however it is not working for me, following is what I am doing:
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePath);
Node pNode = doc.getElementsByTagName(parentNode).item(0);
for (int i = 1; i <= count; i++) {
String nodeValue = value;
Element newNode = doc.createElement(childNode);
newNode.appendChild(doc.createTextNode(nodeValue));
pNode.appendChild(newNode);
}
This is what I am trying to achieve:
<parentNode>
<childNode> value1 </childNode>
<childNode> value2 </childNode>
...
<childNode> valueN </childNode>
</parentNode>
The name of child node is not going to change.
Parent node is not a root node.
Can someone please help me figure out what am I missing.
Thanks.
I checked this for you, it looks like it is working as expected to me. What you have perhaps missed is that the changes to your xml are happening in memory? This is what I've done:
input xml file
<rootNode>
<parentNode></parentNode>
</rootNode>
java test class
import java.io.IOException;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class DocBuilderTest {
private String filePath = "src/test/resource/doc.xml";
#Test
public void builder()
throws ParserConfigurationException, IOException, SAXException, TransformerException {
System.out.println(processFile("parentNode", "value", "childNode"));
}
private String processFile(String parentNode, String value, String childNode)
throws ParserConfigurationException, SAXException, IOException, TransformerException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePath);
Node pNode = doc.getElementsByTagName(parentNode).item(0);
for (int i = 0; i < 5; i++) {
String nodeValue = value + i;
Element newNode = doc.createElement(childNode);
newNode.appendChild(doc.createTextNode(nodeValue));
pNode.appendChild(newNode);
}
return toPrettyPrintString(doc);
}
// From https://stackoverflow.com/a/139096/7421645
private String toPrettyPrintString(Document doc) throws TransformerException {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
// initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
return result.getWriter().toString();
}
}
The pretty print reference if the file is already partially indented.
and output to System.out
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rootNode>
<parentNode>
<childNode>value0</childNode>
<childNode>value1</childNode>
<childNode>value2</childNode>
<childNode>value3</childNode>
<childNode>value4</childNode>
</parentNode>
</rootNode>
NOTE This output is just printed to System.out, I've not overwritten the input file. You'd need to initialise a FileWriter to do that.

update xml with xpath

I want to change the rating of jojo restaurant only , i tried this code but didn't work please help. Below is my xml document and the code I have.
<city>
<beirut>
<restaurant>
<name>sada</name>
</restaurant>
</beirut>
<jbeil>
<restaurant>
<name>toto</name>
<rating>4.3/5</rating>
</restaurant>
<restaurant>
<name>jojo</name>
<rating>4.3/5</rating>
</restaurant>
</jbeil>
<sour>
<restaurant>
<name>sada</name>
</restaurant>
</sour>
</city>
Code:
try {
File inputFile = new File("src/xpath/josephXml.xml");
DocumentBuilderFactory dbFactory
= DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
XPath xPath = XPathFactory.newInstance().newXPath();
String expression = "/City/Jbeil/Restaurants/Restaurant[name='Feniqia']/rating";
Element e = (Element)xPath.evaluate(expression, doc, XPathConstants.NODE);
if (e != null){
e.setTextContent("5/5");
}
} catch (ParserConfigurationException | SAXException | IOException e) {
}
if you only need to write the result (there are other ways):
import java.io.File;
import org.w3c.dom.Document;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
try
{
Transformer trans = TransformerFactory.newInstance().newTransformer();
Result out = new StreamResult(new File("result.xml"));
Source in = new DOMSource(doc);
trans.transform(in, out);
}
catch (Exception exe)
{
System.err.println(exe.getMessage());
}
First, your XPath did not align to your posted XML (no <restaurants> or Feniqia name) and all should have been lower case. Possibly you extracted a piece from large xml document. For demonstration, I used the jojo restaurant.
Second, XPath does not itself update an XML, you will need to create a new document. Simply add a transformation at end:
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import javax.xml.xpath.*;
import java.io.File;
import java.io.IOException;
import org.xml.sax.*;
import org.w3c.dom.*;
public class RatingUpdate {
public static void main(String [] args) {
try {
File inputFile = new File("src/xpath/josephXml.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
XPath xPath = XPathFactory.newInstance().newXPath();
String expression = "/city/jbeil/restaurant[name='jojo']/rating";
Element e = (Element)xPath.evaluate(expression, doc, XPathConstants.NODE);
if (e != null){
e.setTextContent("5/5");
}
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new DOMSource(doc), new StreamResult(new File("src/xpath/josephXml_update.xml")));
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException |
TransformerException e) {
}
}
}

Writing (overriding) same XML file that I read

I made a method to read XML files, but now I need to write or override that same XML file with the same tags, nodes and objects, but with different data inside child nodes.
First I want to make read and write working and then I have some ideas to maybe put the whole XML file into a buffer. Then I could put the whole XML under one class and just write that class again into the same XML this is just an idea, any suggestion or idea is welcome.
My XML file looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Document Root -->
<DATA>
<Settings USERNAME="test" PASSWORD="test" STATUS="active" / >
</DATA>
This is my code for reading:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class Read {
private final static String SETTINGS_LINE = Settings;
public void readXML() {
try {
File xmlFile = new File("Test.xml");
DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(xmlFile);
// Normalize the XML file
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for(int temp = 0; temp < nodeList.getLength(); temp++) {
Node node = nodeList.item(temp);
if(node instanceof Element && node.getNodeName() == SETTINGS_LINE) {
Element settings = (Element) node;
System.out.println("User" +settings.getAttribute("USERNAME"));
System.out.println("Password" +settings.getAttribute("PASSWORD"));
System.out.println("Status" +settings.getAttribute("STATUS"));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
And this is the code for writing that is not working:
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Modify {
private final static String SETTINGS_LINE = "Settings";
public static void main(String argv[]) {
try {
String filepath = "test.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// Normalize the XML File
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Element && node.getNodeName() == SETTINGS_LINE) {
Element settings = (Element) node;
if("USERNAME".equals(node.getChildNodes())){
node.setTextContent("mivnadic");
}
}
// Write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filepath));
transformer.transform(source, result);
}
System.out.println("File saved");
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
}
}

XPath works standalone, but does not work when put in a web app

I am looking to parse the XML, With the help of xpath expression I want to bring in all the node values whose node name is AuditRecord. Surprisingly I can do this in a standalone application but same code fails in the application. I didnt even change the XML. I am using the same XML file in the standalone application and web application I can see results in standlone application but I get 0 nodelist size when I try the same thing in webapplication.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class TestXmlNode {
private static final String TEST_XML = "C:/test.xml";
public static void main(String[] args) throws ParseException {
try {
//XPath xPath = XPathFactory.newInstance().newXPath();
/*System.out.println("*************************");
String expression = "//AuditRecord/DateTimeStamp";;
System.out.println("*************************");
System.out.println(expression);
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
System.out.println("Nodelist size"+nodeList.getLength());
for (int i = 0; i < nodeList.getLength(); i++) {
String date = nodeList.item(i).getFirstChild().getNodeValue();
System.out.println("Date after split "+date.split("T")[0]);
Date thedate = convertStringToDate(date);
Date todate = convertStringToDate("2014-01-01");
System.out.println("XML todate"+todate.toString());
if(thedate.after(todate))
System.out.println("-------------------------->"+ thedate.toString());
}*/
FileInputStream file = new FileInputStream(new File(TEST_XML));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
org.w3c.dom.Document xmlDocument = builder.parse(file);
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression xPathExpr = xpath.compile("//AuditRecord/DateTimeStamp/text()");
Object result = xPathExpr.evaluate(xmlDocument, XPathConstants.NODESET);
print(result);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
public static void print(Object result){
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(i+" "+nodes.item(i).getNodeValue());
}
}
}
Your web app probably doesn't have access to C:/test.xml as web apps generally aren't allowed to access the file system directly.
The presence of xmlparserv-2.0.jar in the classpath is issue, which does not allow to apply xpath expression. Any idea on how to move on

Updating an XML String

From the given XML String, i have to update End Date value .
Even though I'm updating the xml in updateNodeValue() method, my final output xml is same as the input xml.
Can someone tell me what is the mistake in this code
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class MyClass{
static String strXml = "<INFO><BeginDate>2013-12-02</BeginDate><EndDate>2014-01-31</EndDate></INFO>";
public static void main(String[] args) throws Exception {
System.out.println(strXml);
Document doc = StringToDocument(strXml);
updateNodeValue(doc);
String newxml = DocumentToString(doc);
System.out.println(newxml);
}
public static void updateNodeValue(Document doc) {
Node rootNode = doc.getFirstChild();
NodeList list = rootNode.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
Element element = (Element) list.item(i);
Node node = list.item(i);
if ("EndDate".equals(node.getNodeName())) {
element.setNodeValue("2013-12-12");
return;
}
}
}
public static String DocumentToString(Document doc) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
String output = writer.getBuffer().toString();
return output;
}
public static Document StringToDocument(String strXml) throws Exception {
Document doc = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
StringReader strReader = new StringReader(strXml);
InputSource is = new InputSource(strReader);
doc = (Document) builder.parse(is);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return doc;
}
}
Useelement.setTextContent(...) in your updateNodeValue method.
The method you should use is not setNodeValue() but setTextContent()
See http://docs.oracle.com/javase/1.5.0/docs/api/org/w3c/dom/Node.html#setNodeValue(java.lang.String)

Categories

Resources