XPath with namespace in Java - java

I would like to get all the content in between the tags but I do not know how to do this because of the urn: namespace.
<urn:ResponseStatus version="1.0" xmlns:urn="urn:camera-org">
<urn:requestURL>/CAMERA/Streaming/status</urn:requestURL>
<urn:statusCode>4</urn:statusCode>
<urn:statusString>Invalid Operation</urn:statusString>
<urn:id>0</urn:id>
</urn:ResponseStatus>
Any ideas?

Short answer: use XPath local-name(). Like this: xPathFactory.newXPath().compile("//*[local-name()='requestURL']/text()"); will return /CAMERA/Streaming/status
Or you can implement a NamespaceContext that maps namespaces names and URIs and set it on the XPath object before querying.
Take a look at this blog article, Update: the article is down, you can see it on webarchive
Solution 1 sample:
XPath xpath = XPathFactory.newInstance().newXPath();
String responseStatus = xpath.evaluate("//*[local-name()='ResponseStatus']/text()", document);
System.out.println("-> " + responseStatus);
Solution 2 sample:
// load the Document
Document document = ...;
NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
return prefix.equals("urn") ? "urn:camera-org" : null;
}
public Iterator getPrefixes(String val) {
return null;
}
public String getPrefix(String uri) {
return null;
}
};
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(ctx);
String responseStatus = xpath.evaluate("//urn:ResponseStatus/text()", document);
System.out.println("-> " + responseStatus);
Edit
This is a complete example, it correctly retrieve the element:
String xml = "<urn:ResponseStatus version=\"1.0\" xmlns:urn=\"urn:camera-org\">\r\n" + //
"\r\n" + //
"<urn:requestURL>/CAMERA/Streaming/status</urn:requestURL>\r\n" + //
"<urn:statusCode>4</urn:statusCode>\r\n" + //
"<urn:statusString>Invalid Operation</urn:statusString>\r\n" + //
"<urn:id>0</urn:id>\r\n" + //
"\r\n" + //
"</urn:ResponseStatus>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new java.io.ByteArrayInputStream(xml.getBytes()));
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
return prefix.equals("urn") ? "urn:camera-org" : null;
}
public Iterator<?> getPrefixes(String val) {
return null;
}
public String getPrefix(String uri) {
return null;
}
});
XPathExpression expr = xpath.compile("//urn:ResponseStatus");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
Node currentItem = nodes.item(i);
System.out.println("found node -> " + currentItem.getLocalName() + " (namespace: " + currentItem.getNamespaceURI() + ")");
}

XML xpath with Namespace
Simple XML
String namespaceXML = "<?xml version='1.0' ?><information><person id='1'><name>Deep</name><age>34</age><gender>Male</gender></person> <person id='2'><name>Kumar</name><age>24</age><gender>Male</gender></person> <person id='3'><name>Deepali</name><age>19</age><gender>Female</gender></person><!-- more persons... --></information>";
String jsonString = "{}";
String expression = "//information";
Name space XML
String namespaceXML = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><m:NumberToDollarsResponse xmlns:m=\"http://www.dataaccess.com/webservicesserver/\"><m:NumberToDollarsResult>nine hundred and ninety nine dollars</m:NumberToDollarsResult></m:NumberToDollarsResponse></soap:Body></soap:Envelope>";
String jsonString = "{'soap':'http://schemas.xmlsoap.org/soap/envelope/', 'm':'http://www.dataaccess.com/webservicesserver/'}";
String expression = "//m:NumberToDollarsResponse/m:NumberToDollarsResult/text()";
Supply namespace xml file as a string, to asscerionXpath(namespaceXML, jsonString, expression) method and get result in the form of text/node.
text() : nine hundred and ninety nine dollars
node :
<m:NumberToDollarsResult xmlns:m="http://www.dataaccess.com/webservicesserver/">
nine hundred and ninety nine dollars
</m:NumberToDollarsResult>
public static String asscerionXpath(String namespaceXML, String jsonString, String expression){
if(namespaceXML.indexOf("><") > -1) namespaceXML = namespaceXML.replace("><", ">\r\n<");
if(jsonString.indexOf("'") > -1) jsonString = jsonString.replace("'", "\"");
System.out.println("namespaceXML : \n"+namespaceXML);
System.out.println("nsmespaces : \n"+jsonString);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document source = builder.parse( string2Source(namespaceXML) );
XPath xpath = XPathFactory.newInstance().newXPath();
addNameSpaces(jsonString, xpath);
// An XPath expression is not thread-safe. Make sure it is accessible by only one Thread.
XPathExpression expr = xpath.compile(expression);
// The NodeList interface provides the abstraction of an ordered collection of nodes,
NodeList nodes = (org.w3c.dom.NodeList) expr.evaluate(source, XPathConstants.NODESET);;
Node tree_base = nodes.item(0);
return document2String(tree_base);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
System.out.println("If the expression cannot be evaluated.");
}
return "";
}
static InputSource string2Source( String str ) {
InputSource inputSource = new InputSource( new StringReader( str ) );
return inputSource;
}
static void addNameSpaces(String jsonString, XPath xpath) {
JSONParser parser = new JSONParser();
try {
JSONObject namespaces = (JSONObject) parser.parse(jsonString);
if (namespaces.size() > 0) {
final JSONObject declaredPrefix = namespaces; // To access in Inner-class.
NamespaceContext nameSpace = new NamespaceContext() {
// To get all prefixes bound to a Namespace URI in the current scope, XPath 1.0 specification
// --> "no prefix means no namespace"
public String getNamespaceURI(String prefix) {
Iterator<?> key = declaredPrefix.keySet().iterator();
System.out.println("Keys : "+key.toString());
while (key.hasNext()) {
String name = key.next().toString();
if (prefix.equals(name)) {
System.out.println(declaredPrefix.get(name));
return declaredPrefix.get(name).toString();
}
}
return "";
}
public Iterator<?> getPrefixes(String val) {
return null;
}
public String getPrefix(String uri) {
return null;
}
};// Inner class.
xpath.setNamespaceContext( nameSpace );
}
} catch ( org.json.simple.parser.ParseException e) {
e.printStackTrace();
}
}

Related

How can I obtain a list of String with the values with XPath? [duplicate]

I want to read XML data using XPath in Java, so for the information I have gathered I am not able to parse XML according to my requirement.
here is what I want to do:
Get XML file from online via its URL, then use XPath to parse it, I want to create two methods in it. One is in which I enter a specific node attribute id, and I get all the child nodes as result, and second is suppose I just want to get a specific child node value only
<?xml version="1.0"?>
<howto>
<topic name="Java">
<url>http://www.rgagnonjavahowto.htm</url>
<car>taxi</car>
</topic>
<topic name="PowerBuilder">
<url>http://www.rgagnon/pbhowto.htm</url>
<url>http://www.rgagnon/pbhowtonew.htm</url>
</topic>
<topic name="Javascript">
<url>http://www.rgagnon/jshowto.htm</url>
</topic>
<topic name="VBScript">
<url>http://www.rgagnon/vbshowto.htm</url>
</topic>
</howto>
In above example I want to read all the elements if I search via #name and also one function in which I just want the url from #name 'Javascript' only return one node element.
You need something along the lines of this:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(<uri_as_string>);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile(<xpath_expression>);
Then you call expr.evaluate() passing in the document defined in that code and the return type you are expecting, and cast the result to the object type of the result.
If you need help with a specific XPath expressions, you should probably ask it as separate questions (unless that was your question in the first place here - I understood your question to be how to use the API in Java).
Edit: (Response to comment): This XPath expression will get you the text of the first URL element under PowerBuilder:
/howto/topic[#name='PowerBuilder']/url/text()
This will get you the second:
/howto/topic[#name='PowerBuilder']/url[2]/text()
You get that with this code:
expr.evaluate(doc, XPathConstants.STRING);
If you don't know how many URLs are in a given node, then you should rather do something like this:
XPathExpression expr = xpath.compile("/howto/topic[#name='PowerBuilder']/url");
NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
And then loop over the NodeList.
You can try this.
XML Document
Save as employees.xml.
<?xml version="1.0" encoding="UTF-8"?>
<Employees>
<Employee id="1">
<age>29</age>
<name>Pankaj</name>
<gender>Male</gender>
<role>Java Developer</role>
</Employee>
<Employee id="2">
<age>35</age>
<name>Lisa</name>
<gender>Female</gender>
<role>CEO</role>
</Employee>
<Employee id="3">
<age>40</age>
<name>Tom</name>
<gender>Male</gender>
<role>Manager</role>
</Employee>
<Employee id="4">
<age>25</age>
<name>Meghan</name>
<gender>Female</gender>
<role>Manager</role>
</Employee>
</Employees>
Parser class
The class have following methods
List item
A Method that will return the Employee Name for input ID.
A Method that will return list of Employees Name with age greater than the input age.
A Method that will return list of Female Employees Name.
Source Code
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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 Parser {
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("employees.xml");
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
String name = getEmployeeNameById(doc, xpath, 4);
System.out.println("Employee Name with ID 4: " + name);
List<String> names = getEmployeeNameWithAge(doc, xpath, 30);
System.out.println("Employees with 'age>30' are:" + Arrays.toString(names.toArray()));
List<String> femaleEmps = getFemaleEmployeesName(doc, xpath);
System.out.println("Female Employees names are:" +
Arrays.toString(femaleEmps.toArray()));
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
private static List<String> getFemaleEmployeesName(Document doc, XPath xpath) {
List<String> list = new ArrayList<>();
try {
//create XPathExpression object
XPathExpression expr =
xpath.compile("/Employees/Employee[gender='Female']/name/text()");
//evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++)
list.add(nodes.item(i).getNodeValue());
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return list;
}
private static List<String> getEmployeeNameWithAge(Document doc, XPath xpath, int age) {
List<String> list = new ArrayList<>();
try {
XPathExpression expr =
xpath.compile("/Employees/Employee[age>" + age + "]/name/text()");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++)
list.add(nodes.item(i).getNodeValue());
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return list;
}
private static String getEmployeeNameById(Document doc, XPath xpath, int id) {
String name = null;
try {
XPathExpression expr =
xpath.compile("/Employees/Employee[#id='" + id + "']/name/text()");
name = (String) expr.evaluate(doc, XPathConstants.STRING);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return name;
}
}
Getting started example:
xml file:
<inventory>
<book year="2000">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95</price>
</book>
<book year="2005">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<isbn>0743416910</isbn>
<price>5.99</price>
</book>
<book year="1995">
<title>Zodiac</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553573862</isbn>
<price>7.50</price>
</book>
<!-- more books... -->
</inventory>
Java code:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
try {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse (new File("c:\\tmp\\my.xml"));
// normalize text representation
doc.getDocumentElement().normalize();
System.out.println ("Root element of the doc is " + doc.getDocumentElement().getNodeName());
NodeList listOfBooks = doc.getElementsByTagName("book");
int totalBooks = listOfBooks.getLength();
System.out.println("Total no of books : " + totalBooks);
for(int i=0; i<listOfBooks.getLength() ; i++) {
Node firstBookNode = listOfBooks.item(i);
if(firstBookNode.getNodeType() == Node.ELEMENT_NODE) {
Element firstElement = (Element)firstBookNode;
System.out.println("Year :"+firstElement.getAttribute("year"));
//-------
NodeList firstNameList = firstElement.getElementsByTagName("title");
Element firstNameElement = (Element)firstNameList.item(0);
NodeList textFNList = firstNameElement.getChildNodes();
System.out.println("title : " + ((Node)textFNList.item(0)).getNodeValue().trim());
}
}//end of for loop with s var
} catch (SAXParseException err) {
System.out.println ("** Parsing error" + ", line " + err.getLineNumber () + ", uri " + err.getSystemId ());
System.out.println(" " + err.getMessage ());
} catch (SAXException e) {
Exception x = e.getException ();
((x == null) ? e : x).printStackTrace ();
} catch (Throwable t) {
t.printStackTrace ();
}
Here is an example of processing xpath with vtd-xml... for heavy duty XML processing it is second to none. here is the a recent paper on this subject Processing XML with Java – A Performance Benchmark
import com.ximpleware.*;
public class changeAttrVal {
public static void main(String s[]) throws VTDException,java.io.UnsupportedEncodingException,java.io.IOException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("input.xml", false))
return;
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
XMLModifier xm = new XMLModifier(vn);
ap.selectXPath("/*/place[#id=\"p14\" and #initialMarking=\"2\"]/#initialMarking");
int i=0;
while((i=ap.evalXPath())!=-1){
xm.updateToken(i+1, "499");// change initial marking from 2 to 499
}
xm.output("new.xml");
}
}
If you have a xml like below
<e:Envelope
xmlns:d = "http://www.w3.org/2001/XMLSchema"
xmlns:e = "http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wn0 = "http://systinet.com/xsd/SchemaTypes/"
xmlns:i = "http://www.w3.org/2001/XMLSchema-instance">
<e:Header>
<Friends>
<friend>
<Name>Testabc</Name>
<Age>12121</Age>
<Phone>Testpqr</Phone>
</friend>
</Friends>
</e:Header>
<e:Body>
<n0:ForAnsiHeaderOperResponse xmlns:n0 = "http://systinet.com/wsdl/com/magicsoftware/ibolt/localhost/ForAnsiHeader/ForAnsiHeaderImpl#ForAnsiHeaderOper?KExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzs=">
<response i:type = "d:string">12--abc--pqr</response>
</n0:ForAnsiHeaderOperResponse>
</e:Body>
</e:Envelope>
and wanted to extract the below xml
<e:Header>
<Friends>
<friend>
<Name>Testabc</Name>
<Age>12121</Age>
<Phone>Testpqr</Phone>
</friend>
</Friends>
</e:Header>
The below code helps to achieve the same
public static void main(String[] args) {
File fXmlFile = new File("C://Users//abhijitb//Desktop//Test.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document document;
Node result = null;
try {
document = dbf.newDocumentBuilder().parse(fXmlFile);
XPath xPath = XPathFactory.newInstance().newXPath();
String xpathStr = "//Envelope//Header";
result = (Node) xPath.evaluate(xpathStr, document, XPathConstants.NODE);
System.out.println(nodeToString(result));
} catch (SAXException | IOException | ParserConfigurationException | XPathExpressionException
| TransformerException e) {
e.printStackTrace();
}
}
private static String nodeToString(Node node) throws TransformerException {
StringWriter buf = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
xform.transform(new DOMSource(node), new StreamResult(buf));
return (buf.toString());
}
Now if you want only the xml like below
<Friends>
<friend>
<Name>Testabc</Name>
<Age>12121</Age>
<Phone>Testpqr</Phone>
</friend>
</Friends>
You need to change the
String xpathStr = "//Envelope//Header"; to String xpathStr = "//Envelope//Header/*";
This shows you how to
Read in an XML file to a DOM
Filter out a set of Nodes with XPath
Perform a certain action on each of the extracted Nodes.
We will call the code with the following statement
processFilteredXml(xmlIn, xpathExpr,(node) -> {/*Do something...*/;});
In our case we want to print some creatorNames from a book.xml using "//book/creators/creator/creatorName" as xpath to perform a printNode action on each Node that matches the XPath.
Full code
#Test
public void printXml() {
try (InputStream in = readFile("book.xml")) {
processFilteredXml(in, "//book/creators/creator/creatorName", (node) -> {
printNode(node, System.out);
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private InputStream readFile(String yourSampleFile) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(yourSampleFile);
}
private void processFilteredXml(InputStream in, String xpath, Consumer<Node> process) {
Document doc = readXml(in);
NodeList list = filterNodesByXPath(doc, xpath);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
process.accept(node);
}
}
public Document readXml(InputStream xmlin) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xmlin);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private NodeList filterNodesByXPath(Document doc, String xpathExpr) {
try {
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression expr = xpath.compile(xpathExpr);
Object eval = expr.evaluate(doc, XPathConstants.NODESET);
return (NodeList) eval;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void printNode(Node node, PrintStream out) {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(node);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
out.println(xmlString);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Prints
<creatorName>Fosmire, Michael</creatorName>
<creatorName>Wertz, Ruth</creatorName>
<creatorName>Purzer, Senay</creatorName>
For book.xml
<book>
<creators>
<creator>
<creatorName>Fosmire, Michael</creatorName>
<givenName>Michael</givenName>
<familyName>Fosmire</familyName>
</creator>
<creator>
<creatorName>Wertz, Ruth</creatorName>
<givenName>Ruth</givenName>
<familyName>Wertz</familyName>
</creator>
<creator>
<creatorName>Purzer, Senay</creatorName>
<givenName>Senay</givenName>
<familyName>Purzer</familyName>
</creator>
</creators>
<titles>
<title>Critical Engineering Literacy Test (CELT)</title>
</titles>
</book>
Expanding on the excellent answer by #bluish and #Yishai, here is how you make the NodeLists and node attributes support iterators, i.e. the for(Node n: nodelist) interface.
Use it like:
NodeList nl = ...
for(Node n : XmlUtil.asList(nl))
{...}
and
Node n = ...
for(Node attr : XmlUtil.asList(n.getAttributes())
{...}
The code:
/**
* Converts NodeList to an iterable construct.
* From: https://stackoverflow.com/a/19591302/779521
*/
public final class XmlUtil {
private XmlUtil() {}
public static List<Node> asList(NodeList n) {
return n.getLength() == 0 ? Collections.<Node>emptyList() : new NodeListWrapper(n);
}
static final class NodeListWrapper extends AbstractList<Node> implements RandomAccess {
private final NodeList list;
NodeListWrapper(NodeList l) {
this.list = l;
}
public Node get(int index) {
return this.list.item(index);
}
public int size() {
return this.list.getLength();
}
}
public static List<Node> asList(NamedNodeMap n) {
return n.getLength() == 0 ? Collections.<Node>emptyList() : new NodeMapWrapper(n);
}
static final class NodeMapWrapper extends AbstractList<Node> implements RandomAccess {
private final NamedNodeMap list;
NodeMapWrapper(NamedNodeMap l) {
this.list = l;
}
public Node get(int index) {
return this.list.item(index);
}
public int size() {
return this.list.getLength();
}
}
}
Read XML file using XPathFactory, SAXParserFactory and StAX (JSR-173).
Using XPath get node and its child data.
public static void main(String[] args) {
String xml = "<soapenv:Body xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>"
+ "<Yash:Data xmlns:Yash='http://Yash.stackoverflow.com/Services/Yash'>"
+ "<Yash:Tags>Java</Yash:Tags><Yash:Tags>Javascript</Yash:Tags><Yash:Tags>Selenium</Yash:Tags>"
+ "<Yash:Top>javascript</Yash:Top><Yash:User>Yash-777</Yash:User>"
+ "</Yash:Data></soapenv:Body>";
String jsonNameSpaces = "{'soapenv':'http://schemas.xmlsoap.org/soap/envelope/',"
+ "'Yash':'http://Yash.stackoverflow.com/Services/Yash'}";
String xpathExpression = "//Yash:Data";
Document doc1 = getDocument(false, "fileName", xml);
getNodesFromXpath(doc1, xpathExpression, jsonNameSpaces);
System.out.println("\n===== ***** =====");
Document doc2 = getDocument(true, "./books.xml", xml);
getNodesFromXpath(doc2, "//person", "{}");
}
static Document getDocument( boolean isFileName, String fileName, String xml ) {
Document doc = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
if( isFileName ) {
File file = new File( fileName );
FileInputStream stream = new FileInputStream( file );
doc = builder.parse( stream );
} else {
doc = builder.parse( string2Source( xml ) );
}
} catch (SAXException | IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return doc;
}
/**
* ELEMENT_NODE[1],ATTRIBUTE_NODE[2],TEXT_NODE[3],CDATA_SECTION_NODE[4],
* ENTITY_REFERENCE_NODE[5],ENTITY_NODE[6],PROCESSING_INSTRUCTION_NODE[7],
* COMMENT_NODE[8],DOCUMENT_NODE[9],DOCUMENT_TYPE_NODE[10],DOCUMENT_FRAGMENT_NODE[11],NOTATION_NODE[12]
*/
public static void getNodesFromXpath( Document doc, String xpathExpression, String jsonNameSpaces ) {
try {
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
JSONObject namespaces = getJSONObjectNameSpaces(jsonNameSpaces);
if ( namespaces.size() > 0 ) {
NamespaceContextImpl nsContext = new NamespaceContextImpl();
Iterator<?> key = namespaces.keySet().iterator();
while (key.hasNext()) { // Apache WebServices Common Utilities
String pPrefix = key.next().toString();
String pURI = namespaces.get(pPrefix).toString();
nsContext.startPrefixMapping(pPrefix, pURI);
}
xpath.setNamespaceContext(nsContext );
}
XPathExpression compile = xpath.compile(xpathExpression);
NodeList nodeList = (NodeList) compile.evaluate(doc, XPathConstants.NODESET);
displayNodeList(nodeList);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
static void displayNodeList( NodeList nodeList ) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
String NodeName = node.getNodeName();
NodeList childNodes = node.getChildNodes();
if ( childNodes.getLength() > 1 ) {
for (int j = 0; j < childNodes.getLength(); j++) {
Node child = childNodes.item(j);
short nodeType = child.getNodeType();
if ( nodeType == 1 ) {
System.out.format( "\n\t Node Name:[%s], Text[%s] ", child.getNodeName(), child.getTextContent() );
}
}
} else {
System.out.format( "\n Node Name:[%s], Text[%s] ", NodeName, node.getTextContent() );
}
}
}
static InputSource string2Source( String str ) {
InputSource inputSource = new InputSource( new StringReader( str ) );
return inputSource;
}
static JSONObject getJSONObjectNameSpaces( String jsonNameSpaces ) {
if(jsonNameSpaces.indexOf("'") > -1) jsonNameSpaces = jsonNameSpaces.replace("'", "\"");
JSONParser parser = new JSONParser();
JSONObject namespaces = null;
try {
namespaces = (JSONObject) parser.parse(jsonNameSpaces);
} catch (ParseException e) {
e.printStackTrace();
}
return namespaces;
}
XML Document
<?xml version="1.0" encoding="UTF-8"?>
<book>
<person>
<first>Yash</first>
<last>M</last>
<age>22</age>
</person>
<person>
<first>Bill</first>
<last>Gates</last>
<age>46</age>
</person>
<person>
<first>Steve</first>
<last>Jobs</last>
<age>40</age>
</person>
</book>
Out put for the given XPathExpression:
String xpathExpression = "//person/first";
/*OutPut:
Node Name:[first], Text[Yash]
Node Name:[first], Text[Bill]
Node Name:[first], Text[Steve] */
String xpathExpression = "//person";
/*OutPut:
Node Name:[first], Text[Yash]
Node Name:[last], Text[M]
Node Name:[age], Text[22]
Node Name:[first], Text[Bill]
Node Name:[last], Text[Gates]
Node Name:[age], Text[46]
Node Name:[first], Text[Steve]
Node Name:[last], Text[Jobs]
Node Name:[age], Text[40] */
String xpathExpression = "//Yash:Data";
/*OutPut:
Node Name:[Yash:Tags], Text[Java]
Node Name:[Yash:Tags], Text[Javascript]
Node Name:[Yash:Tags], Text[Selenium]
Node Name:[Yash:Top], Text[javascript]
Node Name:[Yash:User], Text[Yash-777] */
See this link for our own Implementation of NamespaceContext

XPath witn namespace - query gives not results

Without using a namespace the XPath example worked fine. A list is printed. With the namespace added, no result is returned.
How can I use namespaces and XPath properly?
My sample (minimalized) xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<nodespace:Employees xmlns:nodespace="my_unique_namespace_name">
<nodespace:Employee id="1">
<nodespace:age>29</nodespace:age>
<nodespace:name>Pankaj</nodespace:name>
<nodespace:gender>Male</nodespace:gender>
<nodespace:role>Java Developer</nodespace:role>
</nodespace:Employee>
<nodespace:Employee id="2">
<nodespace:age>35</nodespace:age>
<nodespace:name>Lisa</nodespace:name>
<nodespace:gender>Female</nodespace:gender>
<nodespace:role>CEO</nodespace:role>
</nodespace:Employee>
</nodespace:Employees>
The XPath Java source code is:
public class XpathNamespaceTest {
public static final String PREFIX_NAME = "bdn";
public static final String NODESPACE_UNIQUE_NAME = "nodespace";
public static void main(String[] args) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
try {
ClassLoader classLoader = new XpathNamespaceTest().getClass().getClassLoader();
URL resource = classLoader.getResource("employees_namespace.xml");
File file = new File( resource.getFile());
builder = factory.newDocumentBuilder();
doc = builder.parse(file);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
#Override
public Iterator getPrefixes(String arg0) { return null; }
#Override
public String getPrefix(String ns) {
if(ns.equals(NODESPACE_UNIQUE_NAME)) {
return PREFIX_NAME;
}
return null;
}
#Override
public String getNamespaceURI(String arg0) {
if (PREFIX_NAME.equals(arg0)) {
return NODESPACE_UNIQUE_NAME;
}
return null;
}
});
List<String> names = getEmployeeNameWithAge(doc, xpath, 30);
System.out.println("Employees with 'age>30' are:" + Arrays.toString(names.toArray()));
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
private static List<String> getEmployeeNameWithAge(Document doc, XPath xpath, int age) {
List<String> list = new ArrayList<>();
try {
XPathExpression expr = xpath.compile("/bdn:Employees/bdn:Employee[bdn:age>" + age + "]/bdn:name/text()");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) list.add(nodes.item(i).getNodeValue());
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return list;
}
}
The namespace URI is my_unique_namespace_name so you need
public static final String NODESPACE_UNIQUE_NAME = "my_unique_namespace_name";

Android xml get node value null

i have a xml
<DatosClientes>
<User>Prueba</User>
<intUserNumber>1487</intUserNumber>
<IdUser>1328</IdUser>
</DatosClientes>
How to read data in android ? when run all time return null in node value
public static void Parse(String response){
try{
DocumentBuilderFactory dbf = DocumentBuilderFactory
.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(response));
Document doc = db.parse(is);
doc.getDocumentElement().normalize();
NodeList datos = doc.getElementsByTagName("DatosClientes");
XmlParse parser = new XmlParse();
for (int i = 0; i < datos.getLength(); i++) {
Node node = datos.item(i);
Element fstElmnt = (Element) node;
NodeList nameList = fstElmnt.getElementsByTagName("User");
Log.e("log",String.valueOf(nameList.item(0).getNodeValue()));
}
}catch (Exception e){
e.printStackTrace();
}
}
my objetive is finally read value and convert into ArrayList
It sounds like you are trying to get a list of the values in the XML? That is, you want:
{ "Prueba", "1487", "1328" }
For that, you can do something like:
public static final String XML_CONTENT =
"<DatosClientes>"
+ "<User>Prueba</User>"
+ "<intUserNumber>1487</intUserNumber>"
+ "<IdUser>1328</IdUser>"
+ "</DatosClientes>";
public static final Element getRootNode(final String xml) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xml)));
return document.getDocumentElement();
} catch (ParserConfigurationException | SAXException | IOException exception) {
System.err.println(exception.getMessage());
return null;
}
}
public static final List<String> getValuesFromXml(final String xmlContent) {
Element root = getRootNode(xmlContent);
NodeList nodes = root.getElementsByTagName("*");
List<String> values = new ArrayList<>();
for (int index = 0; index < nodes.getLength(); index++) {
final String nodeValue = nodes.item(index).getTextContent();
values.add(nodeValue);
System.out.println(nodeValue);
}
return values;
}
public static void main (String[] args) {
final List<String> nodeValues = getValuesFromXml(XML_CONTENT);
}

How to use variables in XPath?

I am using Xpath and Java.
The XML got plenty of OBJECT_TYPES and every object type has properties and parameters.
And each property and parameter got elements.
How do I do the following from my XML file.
I wanna know how to select with the XPATH string expression all property elements depending on whats the name of the OBJECT_TYPE string. The object type string name depends on what name the user selects from the list.
How can I do that?
Should be something like :
String expression = "/getObjType()/prop/*";
But the getObjectType is a method so I cant use it in a string expression.
XML looks something like this:
<type>
<OBJECT_TYPE>SiteData</OBJECT_TYPE>
<prop>
<DESCRIPTION>Site parameters</DESCRIPTION>
<PARENT>NULL</PARENT>
<VIRTUAL>0</VIRTUAL>
<VISIBLE>1</VISIBLE>
<PICTURE>NULL</PICTURE>
<HELP>10008</HELP>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<NAME_FORMAT>NULL</NAME_FORMAT>
</prop>
<param>
<PARAMETER>blabla</PARAMETER>
<DATA_TYPE>INTEGER</DATA_TYPE>
<DESCRIPTION>blaba</DESCRIPTION>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<ORDER1>1</ORDER1>
<NESTED>0</NESTED>
<DEFAULT1>NULL</DEFAULT1>
<FORMAT>0:16382</FORMAT>
</param>
<OBJECT_TYPE>Data</OBJECT_TYPE>
<prop>
<DESCRIPTION>Site parameters</DESCRIPTION>
<PARENT>NULL</PARENT>
<VIRTUAL>0</VIRTUAL>
<VISIBLE>1</VISIBLE>
<PICTURE>NULL</PICTURE>
<HELP>10008</HELP>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<NAME_FORMAT>NULL</NAME_FORMAT>
</prop>
<param>
<PARAMETER>gmgm</PARAMETER>
<DATA_TYPE>INTEGER</DATA_TYPE>
<DESCRIPTION>babla</DESCRIPTION>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<ORDER1>1</ORDER1>
<NESTED>0</NESTED>
<DEFAULT1>NULL</DEFAULT1>
<FORMAT>0:16382</FORMAT>
</param>
</type>
So depending on whats the name of the Object_type I wanna get thoose properties and I have list 122 object types so I have to use a varible to pick which one the user selects.
public class PropXMLParsing {
static PropXMLParsing instance = null;
private List<String> list = new ArrayList<String>();
ObjType obj = new ObjType();
public static PropXMLParsing getInstance() {
if (instance == null) {
instance = new PropXMLParsing();
try {
instance.ParserForObjectTypes();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
return instance;
}
public void ParserForObjectTypes() throws SAXException, IOException,
ParserConfigurationException {
try {
FileInputStream file = new FileInputStream(new File(
"xmlFiles/CoreDatamodel.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xp = XPathFactory.newInstance().newXPath();
final Map<String, Object> vars = new HashMap<String, Object>();
xp.setXPathVariableResolver(new XPathVariableResolver() {
public Object resolveVariable(QName name) {
return vars.get(name.getLocalPart());
}
});
XPathExpression expr = xp
.compile("/type/OBJECT_TYPE[. = $type]/following-sibling::prop[1]");
vars.put("type", obj.getObjectType());
NodeList objectProps = (NodeList) expr.evaluate(xmlDocument,
XPathConstants.NODESET);
System.out.println(objectProps);
for (int i = 0; i < objectProps.getLength(); i++) {
System.out.println(objectProps.item(i).getFirstChild()
.getNodeValue());
list.add(objectProps.item(i).getFirstChild().getNodeValue());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
public String convertListToString() {
StringBuilder sb = new StringBuilder();
if (list.size() > 0) {
sb.append(list.get(0));
for (int i = 1; i < list.size(); i++) {
sb.append(list.get(i));
}
}
return sb.toString();
}
}
Second solution I have tried that aint working neither not printing out anything in the console.
public void ParserForObjectTypes() throws SAXException, IOException,
ParserConfigurationException {
try {
FileInputStream file = new FileInputStream(new File(
"xmlFiles/CoreDatamodel.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.compile(
"//OBJECT_TYPE[text() = '" + obj.getObjectType()
+ "']/following-sibling::prop[1]/*").evaluate(
xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getNodeName() + " = "
+ nodeList.item(i).getTextContent());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
If you want to extract the prop belonging to a specific OBJECT_TYPE you can do that with
/type/OBJECT_TYPE[. = 'some type']/following-sibling::prop[1]
In Java you could build up this XPath expression dynamically using string concatenation but it would be much safer to use an XPath variable if the library you're using can support that (you don't say in the question what library you're using). For example with javax.xml.xpath
XPath xp = XPathFactory.newInstance().newXPath();
final Map<String, Object> vars = new HashMap<String, Object>();
xp.setXPathVariableResolver(new XPathVariableResolver() {
public Object resolveVariable(QName name) {
return vars.get(name.getLocalPart());
}
});
XPathExpression expr = xp.compile("/type/OBJECT_TYPE[. = $type]/following-sibling::prop[1]");
vars.put("type", "Data");
Node dataProps = (Node)expr.evaluate(doc, XPathConstants.NODE);
vars.put("type", "SiteData");
Node siteProps = (Node)expr.evaluate(doc, XPathConstants.NODE);
// taking the value from a variable
vars.put("type", obj.getObjectType());
Node objectProps = (Node)expr.evaluate(doc, XPathConstants.NODE);
This XPATH will select all the elements within the prop element that follows the OBJECT_TYPE with the text SiteData:
//OBJECT_TYPE[text() = 'SiteData']/following-sibling::prop[1]/*
To change the OBJECT_TYPE being selected just construct the XPATH in the code:
String xpath = "//OBJECT_TYPE[text() = '" + getObjType() + "']/following-sibling::prop[1]/*"
Which results in code like this:
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList)xPath.compile("//OBJECT_TYPE[text() = '" + getObjType() + "']/following-sibling::prop[1]/*").evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++)
{
System.out.println(nodeList.item(i).getNodeName() + " = " + nodeList.item(i).getTextContent());
}
That given the XML from the question and when getObjType() returns SiteData prints:
DESCRIPTION = Site parameters
PARENT = NULL
VIRTUAL = 0
VISIBLE = 1
PICTURE = NULL
HELP = 10008
MIN_NO = 1
MAX_NO = 1
NAME_FORMAT = NULL

XML parsing returns null

I am parsing the below XML using the Dom Parser.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<company>
<Staff id="1">
<firstname>Achyut</firstname>
<lastname>khanna</lastname>
<nickname>Achyut</nickname>
<salary>900000</salary>
</Staff>
</company>
If I only need firstName from the XML why is returning null ?
private String getNodeValue(Node node) {
Node nd = node.getFirstChild();
try {
if (nd == null) {
return node.getNodeValue();
}
else {
getNodeValue(nd);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
You must fetch the nodelist and then pass the appropriate Node value as parameter when you call your defined function.
NodeList n = item.getElementsByTagName("Staff");
Then call your function
String firstName = getNodeValue(n.item(0));
First of all, I do not recommend parsing XMLs using DOM traversals. I would recommend you to use the OXMs (JaxB or XMLbeans). But still if you are interested in doing it this way:
Here is the code
public class T2 {
public static void main(String []args) throws ParserConfigurationException, SAXException, IOException{
DocumentBuilder db = null;
String xmlString = "<?xml version='1.0' encoding='UTF-8' standalone='no'?><company> <Staff id='1'> <firstname>Achyut</firstname> <lastname>khanna</lastname> <nickname>Achyut</nickname> <salary>900000</salary> </Staff></company>";
Document doc = null;
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlString));
db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
doc = db.parse(is);
NodeList nodes = doc.getElementsByTagName("firstname");
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i) instanceof Element) {
Node node = (Node) nodes.item(i);
nodes.item(i);
String fName = getCharacterDataFromElement(node);
System.out.println(fName);
}
}
}
private static String getCharacterDataFromElement(Node e) {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
return null;
}
}
The code above prints Achyut
Save yourself a lot of code by using XPath instead:
XPath xp = XPathFactory.newInstance().newXPath();
InputSource in = new InputSource(...);
String fn = xp.evaluate("/company/Staff[#id='1']/firstname/text()", in);
System.out.println(fn);
printts:
Achyut

Categories