Xpath Java unable to get the URL [duplicate] - java

This question already has answers here:
XPath with namespace in Java
(2 answers)
Closed 4 years ago.
Xpath seems to not work. I've already tried a few things, but nothing seems to work. What am I doing wrong?
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(result)));
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//cm:URL/#value");
String msg = expr.evaluate(doc, XPathConstants.STRING).toString();
logger.debug(msg);
The XML I have looks like this:
<ItemXML xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema" xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema">
<DOCUMENTS SCA_DATE="#" SCA_NR="#" cm:PID="#" xmlns:cm="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema" xmlns:ns1="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<cm:properties type="#">
<cm:lastChangeUserid value="#"/>
<cm:lastChangeTime value="#"/>
<cm:createUserid value="#"/>
<cm:createTime value="#"/>
<cm:semanticType value="#"/>
<cm:ACL name="#"/>
<cm:lastOperation name="#" value="#"/>
</cm:properties>
<ns1:CONTRACTS AM="#"/>
<ns1:BASE cm:PID="#" cm:partNumber="#">
<cm:properties type="item" xsi:type="#">
<cm:lastChangeUserid value="#"/>
<cm:lastChangeTime value="#"/>
<cm:createUserid value="#"/>
<cm:createTime value="#"/>
<cm:semanticType value="#"/>
<cm:ACL name="#"/>
<cm:lastOperation name="#" value="#"/>
</cm:properties>
<cm:resourceObject MIMEType="application/pdf" RMName="#" SMSCollName="#" externalObjectName="" originalFileName="#" resourceFlag="#" resourceName="" size="#">
<cm:URL value="https://testurl.com"/>
</cm:resourceObject>
</ns1:BASE>
</DOCUMENTS>
</ItemXML>
I want the value of cm:URL --> https://testurl.com saved as String.
Important: Xpath should find the value regardless of the xml structure.

Without using XPath you can do:
NodeList elementsByTagName = doc.getDocumentElement().getElementsByTagName("cm:URL");
System.out.println("result: " + elementsByTagName.item(0).getAttributes().getNamedItem("value").getNodeValue());

There is issue in following line :-
Document doc = builder.parse(new InputSource(new StringReader(result)));
i tried to print the document, it is giving me output as [#document: null], can you first try to print the document in console and let me know if it is not null.

as suggested by #bangnab use his solution, i tried its 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.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XpathTester {
public static void main(String[] args) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException {
File inputFile = new File("C:\\Users\\Arvind.Carpenter\\Desktop\\input.txt");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList elementsByTagName = doc.getDocumentElement().getElementsByTagName("cm:URL");
//you can iterate over this node list and get all the URL i am printing first one
System.out.println("result: " + elementsByTagName.item(0).getAttributes().getNamedItem("value").getNodeValue());
}
}

Related

Getting all attributes of an xml by using java and Xpath

I have the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.test.com/rest/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<child test="folder" id="2019-05-15-04.52.05.641880A01" />
<child test="folder" id="2019-05-15-04.52.05.901880A02" />
</root>
I want to read the above xml by using Java code and Xpath, retrieve the id's of the child nodes(i.e. id="2019-05-15-04.52.05.641880A01" and id="2019-05-15-04.52.05.901880A02") and store them into List. I tried with the following java code:
InputSource source = new InputSource(new StringReader(xml));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
org.w3c.dom.Document document = db.parse(source);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
return xpath.evaluate(expression, document);
I called the above the above method with the following Xpath along with the input xml:
*[local-name()='root']/*[local-name()='child']/#id
But I am getting only one id, not all the id's. Any idea on how to get all the id's?
I think your Xpath is right. You can verify it with the following test class.
package com.idsk.commons.xsl;
import java.io.IOException;
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.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Test {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("D://NewFile.xml");
// Create XPath
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
XPathExpression expr = xpath.compile("*[local-name()='root']/*[local-name()='child']/#id");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
List<String> ids = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
ids.add(nodes.item(i).getNodeValue()); //store them into List
}
}
}
It will create following output:
2019-05-15-04.52.05.641880A01
2019-05-15-04.52.05.901880A02

get the number of elements in an XML document

I need to get the total number of nodes in an xml file in java ( java dom ...)
In the file below, the total number of elements is 15
<?xml version="1.0" encoding="UTF-8"?>
<personnes>
<etudiant classe="P2">
<nom>CynO</nom>
<prenoms>
<prenom>Nicolas</prenom>
<prenom>Laurent</prenom>
</prenoms>
<age>25</age>
</etudiant>
<etudiant classe="P1">
<nom>Superwoman</nom>
<prenoms>
<prenom>Sia</prenom>
</prenoms>
<age>34</age>
</etudiant>
<etudiant classe="P3">
<nom>Don Corleone</nom>
<age>28</age>
</etudiant>
</personnes>
thank you
Try with following code snippet. It is worked for me.
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class CountNoOfElements{
public static void main(String args[]) throws Exception {
String filepath = "test.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filepath);
NodeList nodeList = doc.getElementsByTagName("*");
int count = nodeList.getLength();
System.out.println("Total of elements : " + count);
}
}

Java Xpath multiple elements with same name of a parent node

I have an xml like below.
<name>
<value>123</value>
<value>456</value>
<value>789</value>
</name>
Now using java's Xpath query I tried below method
NodeList list3 = (NodeList) xpath.evaluate("name/value", element,XPathConstants.NODESET);
But it gives me only first value, how can I print all <value> tags ?
Your XPath expression is correct, there is most likely another problem in your code. You really should provide a complete example which demonstrates your problem.
The following code demonstrates how this would look like:
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class XmlTest {
public static void main(String[] args) throws Exception {
String xml = "<name>\n" +
"<value>123</value>\n" +
"<value>456</value>\n" +
"<value>789</value>\n" +
"</name>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
NodeList list = (NodeList) xpath.evaluate("name/value", doc, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); ++i) {
Node node = list.item(i);
System.out.println(node.getNodeName());
}
}
}
Running this results in the following output:
value
value
value

Source Attachment does not contain the source for the file XPathImpl.class

I searched and could not find this particular issue discussed. I installed eclipse and selenium, and want a way to work with XML. I found several solutions, but the all seem mostly to use a source file that I don't have? I tried downloading jaxb-xjc-2.1.13.jar, which I found in an internet search, but perhaps I don't know how to point it to my code. For this code:
package automationFramework;
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.xpath.*;
then I try to parse an xml:
public static String getElementById(String id) {
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbFactory.newDocumentBuilder();
Document doc = builder.parse(new File("somelocation"));
XPathFactory xpFactory = XPathFactory.newInstance();
XPath xpath = xpFactory.newXPath();
String pwdout = xpath.evaluate("/user[#id='" + id.toUpperCase() + "']/cZAR", doc);
return pwdout;
} catch (Exception e) {
return null;
}
}
etc. When it tries to evaluate the "xpath.evaluate...." line, it throws a "Source Attachment does not contain the source for the file XPathImpl.class"

How to use XPath on xml docs having default namespace

I want to manipulate xml doc having default namespace but no prefix. Is there a way to use xpath without namespace uri just as if there is no namespace?
I believe it should be possible if we set namespaceAware property of documentBuilderFactory to false. But in my case it is not working.
Is my understanding is incorrect or I am doing some mistake in code?
Here is my code:
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(false);
try {
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse("E:/test.xml");
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET);
System.out.println(nl.getLength());
} catch (Exception e) {
e.printStackTrace();
}
Here is my xml:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.mydomain.com/schema">
<author>
<book title="t1"/>
<book title="t2"/>
</author>
</root>
The XPath processing for a document that uses the default namespace (no prefix) is the same as the XPath processing for a document that uses prefixes:
For namespace qualified documents you can use a NamespaceContext when you execute the XPath. You will need to prefix the fragments in the XPath to match the NamespaceContext. The prefixes you use do not need to match the prefixes used in the document.
http://download.oracle.com/javase/6/docs/api/javax/xml/namespace/NamespaceContext.html
Here is how it looks with your code:
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class Demo {
public static void main(String[] args) {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
try {
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse("E:/test.xml");
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new MyNamespaceContext());
NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET);
System.out.println(nl.getLength());
} catch (Exception e) {
e.printStackTrace();
}
}
private static class MyNamespaceContext implements NamespaceContext {
public String getNamespaceURI(String prefix) {
if("ns".equals(prefix)) {
return "http://www.mydomain.com/schema";
}
return null;
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
}
Note:
I also used the corrected XPath suggested by Dennis.
The following also appears to work, and is closer to your original question:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class Demo {
public static void main(String[] args) {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse("E:/test.xml");
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET);
System.out.println(nl.getLength());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Blaise Doughan is right, attached code is correct.
Problem was somewhere elese. I was running all my tests through Application launcher in Eclipse IDE and nothing was working. Then I discovered Eclipse project was cause of all grief. I ran my class from command prompt, it worked. Created a new eclipse project and pasted same code there, it worked there too.
Thank you all guys for your time and efforts.
I've written a simple NamespaceContext implementation (here), that might be of help. It takes a Map<String, String> as input, where the key is a prefix, and the value is a namespace.
It follows the NamespaceContext spesification, and you can see how it works in the unit tests.
Map<String, String> mappings = new HashMap<>();
mappings.put("foo", "http://foo");
mappings.put("foo2", "http://foo");
mappings.put("bar", "http://bar");
context = new SimpleNamespaceContext(mappings);
context.getNamespaceURI("foo"); // "http://foo"
context.getPrefix("http://foo"); // "foo" or "foo2"
context.getPrefixes("http://foo"); // ["foo", "foo2"]
Note that it has a dependency on Google Guava

Categories

Resources