I have some trouble with XPath. For some unknown reason the result I get from my expression is the one from another run of the function.
Here's the constructor of my class:
Wine(Node ndWine){
try{
xpath = XPathFactory.newInstance().newXPath();
}
catch(Exception e)
{}
Node ndName = null;
try{
ndName = (Node)xpath.evaluate("//name", ndWine, XPathConstants.NODE);
}
catch(Exception e)
{}
if (ndName != null)
name = ndName.getTextContent();
}
And here's the XML:
<cellar>
<wine>
<name>Jasnières</name>
</wine>
<wine>
<name>Ballet d'Octobre</name>
</wine>
</cellar>
In the calling method I have another xpath expression that breaks down the document to the list of <wine> elements. The above code is called for each node.
In the debugger I check that on the second run the ndWine node actually contains data from the second node of the document, but the evaluation always returns the Jasnieres value instead of ballet d'octobre, which I can't understand.
Any idea of the root cause?
Starting the XPath expression with // makes it an absolute path. Even though you pass in the <wine> element it ignores it and starts at the document root. Add a . in front to make it a relative path:
.//name
Or better yet, avoid the // syntax if you can. It's best to avoid doing a full descendant-or-self search if you know exactly where the <name> elements will be. If they'll always be directly inside of a <wine> element then use this XPath:
name
Try this piece of code
try {
expr = xpath.compile("/cellar/wine/name");
nodeList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException ignored) {}
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node != null) {
NodeList childNodes = node.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if (childNode.getNodeType() == Node.TEXT_NODE) {
System.out.println(childNode.getNodeValue());
}
}
}
}
Related
I have an XML file as such:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<coffeeOrder>
<addition>null</addition>
<cost>3.0</cost>
<id>1</id>
<links>http://localhost:9080/cs9322.ass2/rest/payment/1</links>
<status>cancelled</status>
<type>espresso</type>
</coffeeOrder>
I am trying to retrieve the value of status.
Currently I have the following:
try {
Document document = loadXMLFromString(orderXML);
NodeList nodeList = document.getDocumentElement().getChildNodes();
// Cycle through nodes, until "status" or "paymentType" element found
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element) node;
System.out.println(orderXML);
System.out.println(elem.toString());
if (type.equals("order") && elem.getNodeName().equals("status")){
status = elem.getNodeValue();
} else if(type.equals("payment") && elem.getNodeName().equals("paymentType")){
status = elem.getNodeValue();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
However, I am finding that I am constantly getting null.
System.out.println(elem.toString());
returns
[status: null]
even though
System.out.println(orderXML);
shows that the status is not null
Would anyone know what I am doing wrong here?
Use getTextContent method instead of getNodeValue. See documentation on Node class.
I have a xml file that looks like this.
<Device>
<Staff>
<Name>ABC</Name>
<Name>Hello</Name>
</Staff>
<Connect>
<Speed>123</Speed>
<Speed>456</Speed>
</Connect>
</Device>
I need help in retrieving the value of name & speed as i have never tried xml before. I am getting null pointer exception whenever I try to retrieve the element values. Any help is appreciated.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// Load the input XML document, parse it and return an instance of the
// Document class.
Document document = builder.parse(new File("C:/Users/AA/Desktop/eclipse/lol/testing.xml"));//change to own directory
NodeList nodeList = document.getDocumentElement().getChildNodes();
System.out.println(nodeList.getLength());
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(i);
Element elem = (Element) node;
// Get the value of the ID attribute.
// String ID = node.getAttributes().getNamedItem("ID").getNodeValue();
// Get the value of all sub-elements.
String name = elem.getElementsByTagName("Name")
.item(0).getChildNodes().item(0).getNodeValue();
Integer speed = Integer.parseInt(elem.getElementsByTagName("Connect")
.item(0).getChildNodes().item(0).getNodeValue());//null pointer exception happens here
staffList.add(new staff(name));
connectList.add(new connect(speed));
}
}
// Print all employees.
for (staff stl : staffList)
{System.out.println("STAFF "+stl.getName());}
for (connect ctl : connectList)
{System.out.println("Connect "+ctl.getSpeed());}
You will have null pointer exceptions because you're assuming that in every iteration of the for loop, the desired nodes have children elements:
String name = elem.getElementsByTagName("Name")
.item(0).getChildNodes().item(0).getNodeValue();
In the above code, you are accessing the first child of a Name element which is a text node (e.g. ABC), and then getting its children nodes, which will cause an exception since there no children elements inside the text node.
Likewise,
Integer speed = Integer.parseInt(elem.getElementsByTagName("Connect")
.item(0).getChildNodes().item(0).getNodeValue());
will cause an exception in one of the iterations of the loop where elem corresponds to Connect itself.
You can try the following code instead:
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(i);
Element elem = (Element) node;
// Get the value of the ID attribute.
// String ID =
// node.getAttributes().getNamedItem("ID").getNodeValue();
// Get the value of all sub-elements.
NodeList nameNodes = elem.getElementsByTagName("Name");
for(int j = 0; j < nameNodes.getLength(); j++) {
Node nameNode = nameNodes.item(j);
staffList.add(new staff(nameNode.getTextContent()));
}
NodeList speedNodes = elem.getElementsByTagName("Speed");
for(int j = 0; j < speedNodes.getLength(); j++) {
Node speedNode = speedNodes.item(j);
connectList.add(new connect(Integer.parseInt(speedNode.getTextContent())));
}
}
P.S.: Try to use class names that start with an uppercase.
You want getTextContent() rather than getNodeValue() - the latter always returns null for element nodes.
See: DOMDocument getNodeValue() returns null (contains an output escaped string)
How do I list the element names at a given level in an xml schema hierarchy? The code I have below is listing all element names at every level of the hierarchy, with no concept of nesting.
Here is my xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="CDA.xsl"?>
<SomeDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:something">
<title>some title</title>
<languageCode code="en-US"/>
<versionNumber value="1"/>
<recordTarget>
<someRole>
<id extension="998991"/>
<addr use="HP">
<streetAddressLine>1357 Amber Drive</streetAddressLine>
<city>Beaverton</city>
<state>OR</state>
<postalCode>97867</postalCode>
<country>US</country>
</addr>
<telecom value="tel:(816)276-6909" use="HP"/>
</someRole>
</recordTarget>
</SomeDocument>
Here is my java method for importing and iterating the xml file:
public static void parseFile() {
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
Document dom = db.parse("D:\\mypath\\somefile.xml");
//get the root element
Element docEle = dom.getDocumentElement();
//get a nodelist of elements
NodeList nl = docEle.getElementsByTagName("*");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("node.getNodeName() is: "+node.getNodeName());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
The output of the above program is:
title
languageCode
versionNumber
recordTarget
someRole
id
addr
streetAddressLine
city
state
postalCode
country
telecom
Instead, I would like to output the following:
title
languageCode
versionNumber
recordTarget
It would be nice to then be able to list the children of recordTarget as someRole, and then to list the children of someRole as id, addr, and telecom. And so on, but at my discretion in the code. How can I change my code to get the output that I want?
You're getting all nodes with this line:
NodeList nl = docEle.getElementsByTagName("*");
Change it to
NodeList nl = docEle.getChildNodes();
to get all of its children. Your print statement will then give you the output you're looking for.
Then, when you iterate through your NodeList, you can choose to call the same method on each Node you create:
NodeList children = node.getChildNodes();
If you want to print an XML-like structure, perhaps a recursive method that prints all child nodes is what you are looking for.
You could re-write the parseFile (I'd rather call it parseChildrenElementNames) method to take an input String that specifies the element name for which you want to print out its children element names:
public static void parseChildrenElementNames(String parentElementName) {
// get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// parse using builder to get DOM representation of the XML file
Document dom = db
.parse("D:\\mypath\\somefile.xml");
// get the root element
NodeList elementsByTagName = dom.getElementsByTagName(parentElementName);
if(elementsByTagName != null) {
Node parentElement = elementsByTagName.item(0);
// get a nodelist of elements
NodeList nl = parentElement.getChildNodes();
if (nl != null) {
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("node.getNodeName() is: "
+ node.getNodeName());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
However, this will only consider the first element that matches the specified name.
For example, to get the list of elements under the first node named someRole, you would call parseChildrenElementNames("someRole"); which would print out:
node.getNodeName() is: id
node.getNodeName() is: addr
node.getNodeName() is: telecom
I have a function I would like to loop through the xml and pull out certain tags.
My xml looks like this:
<Report_Data>
<Report_Entry>
<Company>Test</Company>
<Name>Test Name</Name>
<Division>Test Division</Division>
</Report_Entry>
<Report_Entry>
<Company>Test 2</Company>
<Name>Test Name 2</Name>
<Division>Test Division 2</Division>
</Report_Entry>
<Report_Entry>
<Company>Test 3</Company>
<Name>Test Name 3</Name>
<Division>Test Division 3</Division>
</Report_Entry>
</Report_Data>
Here is my code to loop through:
String comp, name, div, nodeName, NodeValue;
Node node;
try
{
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
InputSource source = new InputSource(new StringReader(coaFULL));
Document doc2 = (Document) xpath.evaluate("/", source, XPathConstants.NODE);
NodeList nodeList = (NodeList) xpath.compile("/Report_Data/Report_Entry").evaluate(doc2, XPathConstants.NODESET);
System.out.println("NODE LIST LENGTH =" + nodeList.getLength());
String nodeName, nodeValue = "";
Node node;
for(int i = 0; i < nodeList.getLength(); i++)
{
node = nodeList.item(i);
node = nodeList.item(i).getFirstChild();
nodeName = node.getNodeName();
nodeValue = node.getChildNodes().item( 0 ).getNodeValue();
if(nodeName.equals("Company"))
{
comp = nodeValue;
}
else if( nodeName.equals("Name"))
{
name = nodeValue;
}
else if(nodeName.equals("Division"))
{
div = nodeValue;
}
System.out.println("COMPANY = " + comp);
System.out.println("NAME = " + name);
System.out.println("DIVISION = " + div);
}
When I run my code, only the first value (company) gets an actual value, everything else is blank. I also tried adding node = nodeList.item(i).getNextSibling(); inside of each if statement to grab the next node, but that did not work.
My nodeList does have items in it, over 1000. Is there a problem with this statement: NodeList nodeList = (NodeList) xpath.compile("/Report_Data/Report_Entry").evaluate(doc2, XPathConstants.NODESET);?
Should it be: NodeList nodeList = (NodeList) xpath.compile("/Report_Data/Report_Entry/*").evaluate(doc2, XPathConstants.NODESET);
I tried it with the /* at the end but that caused the nodeList to have every single node in it. I want to make sure that when I grab a Report_Entry node, that I set the string variables to the correct values that correspond to each other.
==========================================================
Solution: It's ugly but my solution was to just go with one loop and use the second list of children nodes with hard coded values:
for(int i = 0; i < nodeList.getLength(); i++)
{
node = nodeList.item(i);
tempList = node.getChildNodes();
System.out.println("TEMP LIST LENGTH =" + tempList.getLength());
comp = tempList.item(0).getTextContent();
name = tempList.item(1).getTextContent();
div = tempList.item(2).getTextContent();
}
Thanks to #hage for his help.
Maybe it's because your node is only the first child?
node = nodeList.item(i);
node = nodeList.item(i).getFirstChild();
I guess nodeList.item(i) will give you the Report_Entrys and their first child is the Company.
You will need to loop over all children of the Company entry
EDIT (regarding your edit):
tempList.item(x) is the Company, Name, and then Division. When you get the first child of this one, you are at the text node (the actual content). And because you try to get the name of this node, you get the #text output (see this).
To get name and value of the nodes, try this (untested)
nodeName = tempList.item(x).getNodeName();
nodeValue = tempList.item(x).getTextContent();
I have a XML file that looks like this:
<exist:result xmlns:exist="http://exist.sourceforge.net/NS/exist">
<exist:collection name="/db/RCM" created="2013-03-24T09:37:34.957+05:30" owner="admin" group="dba" permissions="rwxrwxrwx">
<exist:resource name="demo2.xml" created="2013-03-24T09:44:13.696+05:30" last-modified="2013-03-24T09:44:13.696+05:30" owner="guest" group="guest" permissions="rw-r--r--"/>
<exist:resource name="demo3.xml" created="2013-03-24T09:45:47.592+05:30" last-modified="2013-03-24T09:45:47.592+05:30" owner="guest" group="guest" permissions="rw-r--r--"/>
<exist:resource name="rcmdemo.xml" created="2013-03-25T11:36:45.659+05:30" last-modified="2013-03-25T11:36:45.659+05:30" owner="guest" group="guest" permissions="rw-r--r--"/>
<exist:resource name="rcmdemo2.xml" created="2013-03-25T11:47:03.564+05:30" last-modified="2013-03-25T11:47:03.564+05:30" owner="guest" group="guest" permissions="rw-r--r--"/>
</exist:collection>
</exist:result>
I want to fetch the name of the XML files, so the output looks like this:
demo2.xml
demo3.xml
rcmdemo.xml
rcmdemo2.xml
I have written the following code:
NodeList nodeList = doc.getElementsByTagName("exist:resource");
for (int i = 0; i < nodeList.getLength(); i++) {
Node n = nodeList.item(i);
Node actualNode = n.getFirstChild();
if (actualNode != null) {
System.out.println(actualNode.getNodeValue());
}
}
But it does not return the output that I want, where am I going wrong?
In this example name is an attribute of the node rather than the name of the node. Please look at the following question for information regarding attributes of nodes, the second answer in particular is what you are looking for i think.
get the the attributes from an XML File using Java
You have to get the attribute from the given node since your name is an attribute of exist:resource.
NodeList nodeList = doc.getElementsByTagName("exist:resource");
for (int i = 0; i < nodeList.getLength(); i++) {
Node n = nodeList.item(i);
Node actualNode = n.getFirstChild();
if (actualNode != null) {
// Will return node value
System.out.println(actualNode.getNodeValue());
// Will return the attribute value
System.out.println(current.getAttributeValue("name"));
}
}