XML parsing using XPath in Java - 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);

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.

Parsing xml for single value with XPath returns empty string

I'm trying to get this value B006PF20EI in this XML
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>...</OperationRequest>
<Items>
<Request>...</Request>
<TotalResults>8</TotalResults>
<TotalPages>1</TotalPages>
<MoreSearchResultsUrl>...</MoreSearchResultsUrl>
<Item>
<ASIN>B006PF20EI</ASIN>
I'm using XPaths like so
public String parseXml(String xmlString){
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse(new InputSource(new StringReader(xmlString)));
XPath xPath = XPathFactory.newInstance().newXPath();
//Node node = (Node) xPath.evaluate("/Items/Item/ASIN", dDoc, XPathConstants.NODE);
//System.out.println(node.getNodeValue());
String value = xPath.evaluate("/ItemSearchResponse/resp/status", dDoc);
return value;
} catch (Exception e) {
Log.e("MYAPP", "exception", e);
return null;
}
}
But it looks like the method is just returning an emptry string
use the good path:
/ItemSearchResponse/Items/Item/ASIN

Retrieve XML Element names with Java from unknown message format

I am parsing XML from lots of JMS messaging topics, so the structure of each message varies a lot and I'd like to make one general tool to parse them all.
To start, all I want to do is get the element names:
<gui-action>
<action>some action</action>
<params>
<param1>blue</param1>
<param2>tall</param2>
<params>
</gui-action>
I just want to retrieve the strings "gui-action", "action", "params", "param1", and "param2." Duplicates are just fine.
I've tried using org.w3c.dom.Node, Element, NodeLists and I'm not having much luck. I keep getting the element values, not the names.
private Element root;
private Document doc;
private NodeList nl;
//messageStr is passed in elsewhere in the code
//but is a string of the full XML message.
doc = xmlParse( messageStr );
root = doc.getDocumentElement();
nl = root.getChildNodes();
int size = nl.getLength();
for (int i=0; i<size; i++) {
log.info( nl.item(i).getNodeName() );
}
public Document xmlParse( String xml ){
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
InputSource is;
try {
//Using factory get an instance of document builder
db = dbf.newDocumentBuilder();
is = new InputSource(new StringReader( xml ) );
doc = db.parse( is );
} catch(ParserConfigurationException pce) {
pce.printStackTrace();
} catch(SAXException se) {
se.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
return doc;
//parse using builder to get DOM representation of the XML file
}
My logged "parsed" XML looks like this:
#text
action
#text
params
#text
Figured it out. I was iterating over only the child nodes, and not including the parent. So now I just filter out the #texts, and include the parent. Derp.
log.info(root.getNodeName() );
for (int i=0; i<size; i++) {
nodeName = nl.item(i).getNodeName();
if( nodeName != "#text" ) {
log.info( nodeName );
}
}
Now if anyone knows a way to get a NodeList of the entire document, that would be awesome.

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.

Create XML document using nodeList

I need to create a XML Document object using the NodeList. Can someone pls help me to do this. This is my Java code:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class ReadFile {
public static void main(String[] args) {
String exp = "/configs/markets";
String path = "testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList)
xPathExpression.evaluate(xmlDocument,
XPathConstants.NODESET);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I want to have an XML file like this:
<configs>
<markets>
<market>
<name>Real</name>
</market>
<market>
<name>play</name>
</market>
</markets>
</configs>
Thanks in advance.
You should do it like this:
you create a new org.w3c.dom.Document newXmlDoc where you store the nodes in your NodeList,
you create a new root element, and append it to newXmlDoc
then, for each node n in your NodeList, you import n in newXmlDoc, and then you append n as a child of root
Here is the code:
public static void main(String[] args) {
String exp = "/configs/markets/market";
String path = "src/a/testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList) xPathExpression.
evaluate(xmlDocument, XPathConstants.NODESET);
Document newXmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
Element root = newXmlDocument.createElement("root");
newXmlDocument.appendChild(root);
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Node copyNode = newXmlDocument.importNode(node, true);
root.appendChild(copyNode);
}
printTree(newXmlDocument);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void printXmlDocument(Document document) {
DOMImplementationLS domImplementationLS =
(DOMImplementationLS) document.getImplementation();
LSSerializer lsSerializer =
domImplementationLS.createLSSerializer();
String string = lsSerializer.writeToString(document);
System.out.println(string);
}
The output is:
<?xml version="1.0" encoding="UTF-16"?>
<root><market>
<name>Real</name>
</market><market>
<name>play</name>
</market></root>
Some notes:
I've changed exp to /configs/markets/market, because I suspect you want to copy the market elements, rather than the single markets element
for the printXmlDocument, I've used the interesting code in this answer
I hope this helps.
If you don't want to create a new root element, then you may use your original XPath expression, which returns a NodeList consisting of a single node (keep in mind that your XML must have a single root element) that you can directly add to your new XML document.
See following code, where I commented lines from the code above:
public static void main(String[] args) {
//String exp = "/configs/markets/market/";
String exp = "/configs/markets";
String path = "src/a/testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList) xPathExpression.
evaluate(xmlDocument,XPathConstants.NODESET);
Document newXmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
//Element root = newXmlDocument.createElement("root");
//newXmlDocument.appendChild(root);
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Node copyNode = newXmlDocument.importNode(node, true);
newXmlDocument.appendChild(copyNode);
//root.appendChild(copyNode);
}
printXmlDocument(newXmlDocument);
} catch (Exception ex) {
ex.printStackTrace();
}
}
This will give you the following output:
<?xml version="1.0" encoding="UTF-16"?>
<markets>
<market>
<name>Real</name>
</market>
<market>
<name>play</name>
</market>
</markets>
you can try the adoptNode() method of Document. Maybe you will need to iterate over your NodeList. You can access the individual Nodes with nodeList.item(i).If you want to wrap your search results in an Element, you can use createElement() from the Document and appendChild() on the newly created Element

Categories