How can i get values of nodes if two nodes are is present under parent node.
Eg: I have the following Xml.
<?xml version="1.0" encoding="UTF-8"?>
<Services xmlns="http://sample.schema.com/abc">
<service>
<name>Sample</name>
<uri>/v9.0/sample.123.com
</uri>
</service>
<service>
<name>Sample 2</name>
</service>
<service>
<name>Sample 3</name>
<uri>/v9.0/sample3.123.com
</uri>
</service>
<service>
<name>Sample 4</name>
<uri>/v9.0/sample4.123.com
</uri>
</service>
<service>
<name>Sample 5</name>
<uri>/v9.0/sample5.123.com
</uri>
</service>
<service>
<name>Sample 6</name>
</service>
<service>
<name>Sample 7</name>
<uri>/v9.0/sample7.123.com
</uri>
</service>
<service>
<name>Sample 8</name>
</service>
</Services>
My Code:
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 SimpleXpath {
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(false); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("testService1.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//Services/service[(name) and (uri)/text()]");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
String value=nodes.item(i).getNodeValue();
System.out.println(" output : "+i+" "+value);
}
}
}
I want to read the values of name and url from th above xml, If the name and uri is present under the service node.
We can see that some of the service node only contains the name. I want to avoid those one. My xpath expression gives null value as output.
How can i get the "text" of name and uri if service contains both?
Can i get the output as name as first and uri as second using an xpath(If both present under service)?
Thnanks a lot.
John
First of all, you could just use simpler xpath: //Services/service[name and uri]. Then NodeList returns you a list of service elements. You could iterate other its children and find elements named name and uri, then take their text values. Or you could create two more xpath expressions like this:
XPathExpression exprName = xpath.compile("normalize-space(name)");
String name = (String)exprName.evaluate(serviceNode, XPathConstants.STRING);
and the same for uri.
Thank you all....
The following code fulfills the requirement.
If there any other option to improve the quality please suggest.
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(false); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("testService1.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//Services/service[(name) and (uri)]/name/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
XPathExpression expr1 = xpath.compile("//Services/service[(name) and (uri)]/uri/text()");
Object result1 = expr1.evaluate(doc, XPathConstants.NODESET);
NodeList nodes1 = (NodeList) result1;
for (int i = 0; i < nodes1.getLength()&&i < nodes.getLength(); i++) {
String value=nodes.item(i).getNodeValue();
String value1=nodes1.item(i).getNodeValue();
System.out.println(" output : "+i+" "+value+ " "+ value1);
}
}
This xpath select elements that has 2 children
//*[count(*)=2]
for(int j=0; j<children.getLength();j++) {
if (children.item(j) instanceof Element == false)
continue;
NamedNodeMap n = children.item(j).getAttributes();
passwordTagAttr=(Attr) n.getNamedItem("name");
passwordTagAttr=(Attr) n.getNamedItem("uri");
passwordTag=stopTagAttr.getValue();
passwordList.add(passwordTag);
}
Related
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
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);
}
}
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
i know there are plenty of this topic in this page but sadly, i still cant get my solution..
here is my xml code:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Request xmlns:ns1="http://www.sea.com">
<ns1:PayrollRequest>
<ns1:PayrollCost>
<ns1:PayrollID>123</ns1:PayrollID>
<ns1:BatchID>7770</ns1:BatchID>
<ns1:CompanyId>001</ns1:CompanyId>
<ns1:GrossPay>60000</ns1:GrossPay>
</ns1:PayrollCost>
</ns1:PayrollRequest>
</ns1:Request>
and this is my code in java:
import org.w3c.dom.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import java.io.IOException;
import org.xml.sax.SAXException;
public class XPathTry {
public static void main(String[] args)
throws ParserConfigurationException, SAXException,
IOException, XPathExpressionException {
DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("SamplePayroll2.xml");
XPath xpath = XPathFactory.newInstance().newXPath();
// display all
XPathExpression expr = xpath.compile("//PayrollCost/*/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
}
}
ya, as usual, i cant get the output as it only displays:
Process exited with exit code 0.
the output will only display when i remove the ns:1 which the code for the xml will be like this:
<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns:ns1="http://www.sea.com">
<PayrollRequest>
<PayrollCost>
<PayrollID>123</PayrollID>
<BatchID>7770</BatchID>
<CompanyId>001</CompanyId>
<GrossPay>60000</GrossPay>
</PayrollCost>
</PayrollRequest>
</Request>
The problem is, all the suggestions i found in the net none seems to be working:
for example, i already tried the
/*/namespace::*[name()='']
//*[local-name() = 'Element' and namespace-uri() = namespace-uri(/*)]
/*[local-name()=' ']/*[local-name()=' ']/*[local-name()=' ']
etc2..
the only best output i can get is, it will display:
null
can anyone give me the correct code for my problem?
Thanks in Advance!
You are going to have to create a subclass of javax.xml.namespace.NamespaceContext and set it on xpath:
xpath.setNamespaceContext(new NamespaceContext() {
#SuppressWarnings("rawtypes")
#Override
public Iterator getPrefixes(final String namespaceURI) {
return Collections.singleton("ns1").iterator();
}
#Override
public String getPrefix(final String namespaceURI) {
return "ns1";
}
#Override
public String getNamespaceURI(final String prefix) {
return "http://www.sea.com";
}
});
Then you can add the namespace prefix to the XPath expression:
XPathExpression expr = xpath.compile("//ns1:PayrollCost/*/text()");
You need to use a NamespaceContext for your XPath expression. You can read more about how to do this here
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