parsing xml string in java - java

I have been trying to use code I found from other posts, to parse an xml string but when trying to get to the node elements I keep getting null values. Can someone see the error or something I am missing?
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(post));
Document doc;
try {
doc = db.parse(is);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList nodes = root.getElementsByTagName("entry");
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
the root element is null and nodelist null as well. The XML post starts with:
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:activity="http://activitystrea.ms/spec/
1.0/" xmlns:service="http://activitystrea.ms/
service-provider" xmlns:thr="http://purl.org/syndication/thread/1.0"
xmlns:gnip="http://www.post.com/schemas/2010"
xmlns:geo="http://www.georss.org/georss" xmlns:poco="http://portablecontacts.net/spec/1.0">
<id>...
EDIT:
NodeList nodes.. //The value of the local nodes is not used
[entry: null]
// it skips the following lines...
for(int i=0; i < nodes.getLength() - 1; i++){
System.out.println(nodes.item(i).toString());
}

replace NodeList nodes = root.getElementsByTagName("entry");
by NodeList nodes = root.getChildNodes();

Related

Xpath - why only 1 value returned?

Given the xml snippet:
<AddedExtras>
<AddedExtra Code="1234|ABCD" Quantity="1" Supplier="BDA"/>
<AddedExtra Code="5678|EFGH" Quantity="1" Supplier="BDA"/>
<AddedExtra Code="9111|ZXYW" Quantity="1" Supplier="BDA"/>
</AddedExtras>
The following XPath expression:
//*["AddedExtra"]/#Code
when run through a checker evaluates to:
Attribute='Code=1234|ABCD'
Attribute='Code=5678|EFGH'
Attribute='Code=9111|ZXYW'
Why then, does the following code only return the first line?
private String allCodes = "//*["AddedExtra"]/#Code";
get my XML from system and parse it into a Doc:
public Document parseResponse(String response){
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
//Create a document reader and an XPath object
try {
builder = factory.newDocumentBuilder();
doc = builder.parse(new InputSource((new StringReader(response))));
} catch (ParserConfigurationException | org.xml.sax.SAXException | IOException e) {
e.printStackTrace();
}
return doc;
}
Get the new doc:
public Document getParsedResponse(String response) {
return parseResponse(response);
}
Return the Xpath value from the doc:
public String getAllCodeOptions(String response){
Document doc = getParsedResponse(response);
return getNodeValueFromNodeList(doc, allCodes);
}
new method to read the XML nodes:
public String getNodeValueFromNodeList(Document doc, String expression){
NodeList nodeList = null;
String nodes = null;
try {
nodeList = (NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
for(int i=0; i < nodeList.getLength(); i++){
Node node = nodeList.item(i);
nodes = node.getNodeValue();
}
return nodes;
}
returns:
Attribute='Code=1234|ABCD'
You would require to use right evaluate method which takes return type as an argument. Something like below,
NodeSet result = (NodeSet)e.evaluate(e, doc, XPathConstants.NODESET);
for(int index = 0; index < result.getLength(); index ++)
{
Node node = result.item(index);
String name = node.getNodeValue();
}
The problem is that you are asking for only one value.
Try this:
NodeList nodeList = (NodeList)e.evaluate(doc, XPathConstants.NODESET);
for multiple values.
See http://viralpatel.net/blogs/java-xml-xpath-tutorial-parse-xml/ for a tutorial.

How to parse a XML and update it when we are complicated hericarchy?

Suppose I am having following XML File content
<CREDENTIALS>
<SCENERIOONE>
<USERNAME>stackoverflow</USERNAME>
<PASSWORD>argmishra</PASSWORD>
</SCENERIOONE>
<SCENERIOTWO>
<USERNAME>stackexchnage</USERNAME>
<PASSWORD>mishraarg</PASSWORD>
</SCENERIOTWO>
</CREDENTIALS>
I want to retrieve the data for SCENERIOONE(Username and password) and check it and update it if required and similarly for SCENERIOTWO.
I am able to retrieve data if i replaced SCENERIOTWO with SCENERIOONE i.e. child node of CREDENTIALS are same.
But not able to retrieve if child node of one parent node is different.
EDIT:
Now I am able to retrieve the Data from XML by passing Scenario's:-
try {
File file = new File("D://DemoWorkSpace//XMLDemo//lib//MyXMLFile.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
System.out.println("Root element " + doc.getDocumentElement().getNodeName());
NodeList nodeLst = doc.getElementsByTagName("MEMBER_BENEFITS");
System.out.println("Information of all employees");
for (int s = 0; s < nodeLst.getLength(); s++) {
Node fstNode = nodeLst.item(s);
if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
Element fstElmnt = (Element) fstNode;
NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("USERNAME");
Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
NodeList fstNm = fstNmElmnt.getChildNodes();
System.out.println("User Name : " + ((Node) fstNm.item(0)).getNodeValue());
NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("PASSWORD");
Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
NodeList lstNm = lstNmElmnt.getChildNodes();
System.out.println("Password : " + ((Node) lstNm.item(0)).getNodeValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
But I do not know how to update the XML file?
If I understand correctly, what you're really after is the username/password nodes, regardless of where they are in the document....
You can use XPath to query the document to return what you want, for example...
try (InputStream is = TestXML.class.getResourceAsStream("/Credentials.xml")){
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(is);
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression xExpress = xpath.compile("//*[USERNAME and PASSWORD]/*");
NodeList nodeList = (NodeList) xExpress.evaluate(dom, XPathConstants.NODESET);
for (int index = 0; index < nodeList.getLength(); index++) {
Node node = nodeList.item(index);
System.out.println(node.getNodeName());
}
} catch (Exception exp) {
exp.printStackTrace();
}
Will output...
USERNAME
PASSWORD
USERNAME
PASSWORD
If it's important, you can use the Nodes parent property to find the parent node and obviously, getTextContent to get the nodes text content
You can manipulate the nodes like normal, based on your needs
Updated
So, based on comments, you should be able to do something like...
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(new File("Credentials.xml"));
XPath xpath = XPathFactory.newInstance().newXPath();
String scenerio = "SCENERIOONE";
XPathExpression xExpress = xpath.compile("/CREDENTIALS/" + scenerio + "/[USERNAME and PASSWORD]/*");
NodeList nodeList = (NodeList) xExpress.evaluate(dom, XPathConstants.NODESET);
for (int index = 0; index < nodeList.getLength(); index++) {
Node node = nodeList.item(index);
System.out.println(node.getNodeName());
}
} catch (Exception exp) {
exp.printStackTrace();
}
Which will return the USERNAME and PASSWORD nodes for SCENERIOONE
You can use node.get/setTextContent to get/set the text as per normal.
And when you need to, you can use something like...
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty(OutputKeys.METHOD, "xml");
tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
StreamResult result = new StreamResult(new File("Credentials.xml"));
tf.transform(dom, result);
To save it...
$server_output = "<CREDENTIALS>
<SCENERIOONE>
<USERNAME>stackoverflow</USERNAME>
<PASSWORD>argmishra</PASSWORD>
</SCENERIOONE>
<SCENERIOTWO>
<USERNAME>stackexchnage</USERNAME>
<PASSWORD>mishraarg</PASSWORD>
</SCENERIOTWO>
</CREDENTIALS>";
$xml = simplexml_load_string($server_output);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
foreach ($array as $key => $value) {
$username = $value['USERNAME'];
$password = $value['PASSWORD'];
}
Here is the output:
stackoverflow
argmishra
stackexchnage
mishraarg

XML parsing using XPath in Java

Hi!
I've spent some time to parse an XML document with XPath. It seeams to be a simple task but I got in troubles since the begining.
My code is :
public class QueryXML3 {
public static void main(String[] args) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
try {
builder = factory.newDocumentBuilder();
//doc = builder.parse("SampleExample.xml");
InputStream is = QueryXML3.class.getClassLoader().getResourceAsStream("SampleXml.xml");
doc = builder.parse(is);
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
Node parNode = getParameterNode(doc, xpath);
System.out.println("parameter node:" + parNode);
NodeList res = getParameterNodeList(doc, xpath );
System.out.println("List of nodes" + res);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
public static Node getParameterNode(Document doc, XPath xpath) {
Node res = null;
try {
res = (Node) xpath.evaluate("/definitions/process", doc, XPathConstants.NODE);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return res;
}
public static NodeList getParameterNodeList(Document doc, XPath xpath) {
NodeList nodeList = null;
try {
nodeList = (NodeList) xpath.evaluate("/definitions/process", doc, XPathConstants.NODESET);
for (int i = 0; i > nodeList.getLength(); i++) {
System.out.print(nodeList.item(i).getNodeName() + " ");
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return nodeList;
}
}
As a result i get this:
parameter node:[process: null]
List of nodes com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList#2f17aadf
I just want to output all the nodes of my xml file and theire attributes...
You are really asking how to serialize an Element to a string - use either a Transformer or DOMImplementationLS.
The NodeList type has no toString() contract and the implementation does not override the default Object.toString(). You need to iterate over the nodes and serialize each Element as above.
You could easily parse an XML file in java using a 3rd party package such as JSoup or JDom.
As an example, here is some simple output of an XML files elements using JSoup:
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Java code printing all elements and the selected <from>-element:
String xml = "<note>\n"
+ "<to>Tove</to>\n"
+ "<from>Jani</from>\n"
+ "<heading>Reminder</heading>\n"
+ "<body>Don't forget me this weekend!</body>\n"
+ "</note>";
Document doc = Jsoup.parse(xml, "", Parser.xmlParser());
for (Element e : doc.children()) {
System.out.println(e);
}
Element fromElement = doc.select("from").first();
System.out.println("\nThis is the <from>-element content:\n" + fromElement);

Search a attribute in a xml document with java and XPath

i have the following method in java:
private static String getAttributValue(String attribute, String xmlResponseBody) {
String searchAttributeValue = "";
try {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new InputSource(new StringReader(xmlResponseBody)));
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
try {
XPathExpression expr = xpath.compile("#" + attribute);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodeList = (NodeList) result;
Node node = nodeList.item(0); // something wrong??
searchAttributeValue = node.getTextContent();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
return searchAttributeValue;
}
I search an attribute (parameter "attribute") in a xml document (parameter "xmlResponseBody"). I would like to use XPath to solve this task. At the code, which i have comment with "// something wrong", the variable node is null. What should i do? What is the mistake in my code?
Thanks !
Marwief
It is hard to answer this without seeing the sample xml(or part of it), but you can search for an attribute using
xpath.compile("//#" + attribute)
It means search for attribute named attribute inside context node and its descendants. You can get more information here.

Issue with XML child nodes iteration when mix of text and element nodes

I was trying to parse following strings to form a xml document and then trying to extract all child nodes of and add to a different document object which is already available to me.
<dhruba><test>this</test>that<test2>wang chu</test2> something.... </dhruba>
<dhruba>this is text node <test>this</test>that<test2>wang chu</test2> anything..</dhruba>
while I am trying to read the child nodes, it is returning null child for TEXT_NODE for 1st string and null for ELEMENT_NODE for 2nd String, this is wrong, is it API problem ??
I am using following code ... it compile , I am using java 6.
Node n = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
dom = db.newDocument();
Element rootEle = dom.createElement("resources");
// adding the root element to the document
dom.appendChild(rootEle);
Element element = dom.createElement("string");
element.setAttribute("name", "some_name");
try {
n = db.parse(new InputSource(new StringReader("<dhruba><test>this</test>that<test2>node value</test2> some text</dhruba>"))).getDocumentElement();
n = dom.importNode(n, true);
NodeList nodeList = n.getChildNodes();
int length = nodeList.getLength();
System.out.println("Total no of childs : "+length);
for(int count = 0 ; count < length ; count++ ){
Node node = nodeList.item(count);
if(node != null ){
element.appendChild(node);
}
}
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rootEle.appendChild(element);
INPUT :: as string
<dhruba><string name="some_name">
that
<test>this</test>
<test2>node value</test2>
some text
</string>
</dhruba>
EXPECTED OUTPUT :: as document
<string>
<string name="some_name">
<test>this</test>
<test2>node value</test2>
</string>
</string>
if I try to parse
<test>this</test>that<test2>wang chu</test2> something....
then output comes as "thiswang chu"
Why is this happening? what needs to be done if I want to add following node under another document element, i.e. <string>.
<test>this</test>
that
<test2>node value</test2>
some text
[notice that it does not have <dhruba>] inside parent node of another
document.
Hope I am clear. Above code compiles in Java 6
I will assume that this is Java.
First, I'm surprised that you don't get an exception with your importNode() call, since you're importing the Document, which shouldn't be allowed (per the JavaDoc).
Now to the question that you asked: if you only want to attach specific node types, you need to make a test using the node's type. A switch statement is the easiest (note: this has not been compiled, may contain syntax errors):
switch (n.getNodeType())
{
case ELEMENT_NODE :
// append the node to the other tree
break;
default :
// do nothing
}
Probably you want Node.cloneNode() method:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.newDocument();
Element element = dom.createElement("string");
element.setAttribute("name", "some_name");
String inputXMLString =
"<dhruba><test>this</test>that<test2>node value</test2> some text</dhruba>";
Node n = db.parse(new InputSource(new StringReader(inputXMLString))).getDocumentElement();
n = dom.importNode(n, true);
NodeList nodeList = n.getChildNodes();
for (int i = 0; i < nodeList.getLength(); ++i)
{
Node node = nodeList.item(i);
element.appendChild(node.cloneNode(true));
}
dom.appendChild(element);
To get dom into stdout or file you could write:
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(dom);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
Result:
<string name="some_name">
<test>this</test>that<test2>node value</test2> some text</string>

Categories