Issues with xpath context - java

I have a simple xml document:
<Results>
<Result>
<Number>1</Number>
<Data>a</Data>
</Result>
<Result>
<Number>2</Number>
<Data>b</Data>
</Result>
</Results>
I'm trying to get the data and number of each result using this code:
XPathExpression resExpr = xpath
.compile("//Results/Result");
XPathExpression numExpr=xpath
.compile("//Result/Number");
XPathExpression dataExpr=xpath
.compile("//Result/Data");
NodeList nodeList = (NodeList) resExpr.evaluate(root_node,
XPathConstants.NODESET);
for (int i=0;i<nodeList.getLength();i++) {
Node result=nodeList.item(i);
if (result!=null) {
Node numNode=(Node) numExpr.evaluate(result,
XPathConstants.NODE);
Node dataNode=(Node) dataExpr.evaluate(result,
XPathConstants.NODE);
String data=dataNode.getTextContent());
String num=numNode.getTextContent());
}
}
However, I get 1/a on both iterations. It seem that passing a node doesn't make xpath use it as context, but rather it's looking at whole tree?

This is because your xpath expression start with //. This means start searching from document root any child.
To access child of current node try .// for child in any deep, or ./ for direct child.
Or, because the current not in iteration is Result you can use:
XPathExpression numExpr=xpath
.compile("Number");
XPathExpression dataExpr=xpath
.compile("Data");

Related

How to insert compleate java NodeList into xml document?

I would like to add complete NodeList into xml document:
I get my NodeList from document1 as follow:
NodeList myNList=doc1.getElementsByTagName("APPLICATION");
This nodeList contains some nodes with many attributes and I would like to insert this nodeList into other document doc2 in node USER with the name "Nina"
doc2.xml:
<document>
<USER name="Nina">
// nodeList should be inserted here
</USER>
What is the best way do do this without having to create new elements/nodes in doc2?

Extracting the node values in XML with XPath in Java

I have an XML document:
<response>
<result>
<phone>1233</phone>
<sys_id>asweyu4</sys_id>
<link>rft45fgd</link>
<!-- Many more in result -->
</result>
<!-- Many more result nodes -->
</response>
The XML structure is unknown. I am getting XPath for attributes from user.
e.g. inputs are strings like:
//response/result/sys_id , //response/result/phone
How can I get these node values for whole XML document by evaluating XPath?
I referred this but my xpath is as shown above i.e it does not have * or text() format.
The xpath evaluator works perfectly fine with my input format, so is there any way I can achieve the same in java?
Thank you!
It's difficult without seeing your code... I'd just evaluate as a NodeList and then call getTextContent() on each node in the result list...
String input = "<response><result><phone>1233</phone><sys_id>asweyu4</sys_id><link>rft45fgd</link></result><result><phone>1233</phone><sys_id>another-sysid</sys_id><link>another-link</link></result></response>";
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new ByteArrayInputStream(input.getBytes("UTF-8")));
XPath path = XPathFactory.newInstance().newXPath();
NodeList node = (NodeList) path.compile("//response/result/sys_id").evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < node.getLength(); i++) {
System.out.println(node.item(i).getTextContent());
}
Output
asweyu4
another-sysid

Using Document Nodes in Java

I'm trying to read an xml file, for example: http://www1.skysports.com/feeds/11095/news.xml
I need to be able to getTextContent() for all the titles, descriptions etc that are children of <item> tags. There is a <title> tag that is not a child of an <item> tag that i dont want to getTextContent() for.
I've set up my XML reader so that i have:
Document doc = dbuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
String Title = document.getElementsByTagName("title").item(0).getTextContent();
but this method picks up the <title> that isnt a child of <item>
I could just change the item(0) to item(1) but I need this algorithm to work with various XML files that wont necessarily have the initial <title> without the <item> parent.
how can I just select those <title>s that are children of <item>s?
Use XPath instead. Makes it all a lot easier:
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
NodeList nl = (NodeList) xp.evaluate("//item/title/text()", doc,
XPathConstants.NODESET);
for (int i = 0; i < nl.getLength(); ++i) {
System.out.println(nl.item(i).getNodeValue());
}

Java XPath: Get all the elements that match a query

I want to make an XPath query on this XML file (excerpt shown):
<?xml version="1.0" encoding="UTF-8"?>
<!-- MetaDataAPI generated on: Friday, May 25, 2007 3:26:31 PM CEST -->
<Component xmlns="http://xml.sap.com/2002/10/metamodel/webdynpro" xmlns:IDX="urn:sap.com:WebDynpro.Component:2.0" mmRelease="6.30" mmVersion="2.0" mmTimestamp="1180099591892" name="MassimaleContr" package="com.bi.massimalecontr" masterLanguage="it">
...
<Component.UsedModels>
<Core.Reference package="com.test.test" name="MasterModel" type="Model"/>
<Core.Reference package="com.test.massimalecontr" name="MassimaleModel" type="Model"/>
<Core.Reference package="com.test.test" name="TravelModel" type="Model"/>
</Component.UsedModels>
...
I'm using this snippet of code:
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document document = builder.parse(new File("E:\\Test branch\\test.wdcomponent"));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
...(omitted)
System.out.println(xpath.evaluate(
"//d:Component/d:Component.UsedModels/d:Core.Reference/#name",
document));
What I'm expecting to get:
MasterModel
MassimaleModel
TravelModel
What I'm getting:
MasterModel
It seems that only the first element is returned. How can I get all the occurrences that matches my query?
You'll get a item of type NodeList
XPathExpression expr = xpath.compile("//Core.Reference");
NodeList list= (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
System.out.println(node.getTextContent());
// work with node
See How to read XML using XPath in Java
As per that example, If you first compile the XPath expression then execute it, specifying that you want a NodeSet back you should get the result you want.

How do I remove all selected nodes from an XPath?

I run an XPath in Java with the following xml and code:
<?xml version="1.0" encoding="UTF-8"?>
<list>
<member name="James">
<friendlist>
<friend>0001</friend>
<friend>0002</friend>
<friend>0003</friend>
</friendlist>
</member>
<member name="Jamie">
<friendlist>
<friend>0003</friend>
<friend>0002</friend>
<friend>0001</friend>
</friendlist>
</member>
<member name="Katie">
<friendlist>
<friend>0001</friend>
<friend>0003</friend>
<friend>0004</friend>
</friendlist>
</member>
</list>
Code:
try {
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression pathExpr = xpath.compile("/list/member/friendlist/friend[.='0003']");
} catch (XPathExpressionException e) {
Of course there are more codes after this but I didn't paste it here because it thought it may confuse even more.
But the idea is I wish to select all the friend nodes that have the ID 0003 from all the members' friendlist nodes, and then remove it from the XML file. The XPath works by selecting all the "friend" nodes that have the value=0003. I know I can use the removeChild() method of the XML Document object. But the problem is how do I remove all of it directly, without going through layers of loops starting from its parent? The removeChild() method needs me to know its parent's parent's parent.
Thanks!
Update:
This is how I used my XPath:
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression pathExpr = null;
try {
pathExpr = xpath.compile("/list/member/friendlist/friend[.='0003']");
} catch (XPathExpressionException e) {
e.printStackTrace();
}
NodeList list = null;
try {
list = (NodeList) pathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
The xmlDoc is an XML document object that has an XML file parsed. The XML works fine. It is only the XML not returning a reference but a whole new nodelist, which makes it impossible for me to refer back to its original xml document to do amendments.
for each node in the returned NodeList:
n.getParentNode().removeChild(n);
I don't understand why the returned nodelist's nodes are returning null for parentNode().
But you could try first selecting all the parents of the nodes you want to remove, with this XPath expression:
"/list/member/friendlist[friend[.='0003']]"
or the equivalent,
"/list/member/friendlist[friend = '0003']]"
Then iterate through the resulting nodelist, and in the context of each one, query for nodes matching the XPath expression
"friend[.='0003']"
That will give you a parent node and a child node to use with removeChild().
Have a look on XUpdate. It's not pretty, but it works.

Categories

Resources