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"));
}
}
Related
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)
There are two types of items returned:
<LineStatus ID="0" StatusDetails="">
<BranchDisruptions/>
<Line ID="1" Name="Bakerloo"/>
<Status ID="GS" CssClass="GoodService" Description="Good Service" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</LineStatus>
or
<LineStatus ID="5" StatusDetails="Severe delays">
<BranchDisruptions>
<BranchDisruption>
<StationTo ID="106" Name="High Barnet"/>
<StationFrom ID="35" Name="Camden Town"/>
<Status ID="SD" CssClass="DisruptedService" Description="Severe Delays" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</BranchDisruption>
</BranchDisruptions>
<Line ID="5" Name="Northern"/>
<Status ID="SD" CssClass="DisruptedService" Description="Severe Delays" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</LineStatus>
As you can see, the second element also has BranchDisruptions details filled in.
I need to build three ArrayList<String> after parsing the XML response, one containing all the LineStatus StatusDetails, one containing Line Name and one list containing all the Line Status Description.
My problem is that I want to ignore the Status from <BranchDisruption> since I don't need it. So far I have managed to get the list with all the names, but the list with statuses contains Branch statuses also.
nodelist = doc.getElementsByTagName("LineStatus");
for (int i = 0; i < nodelist.getLength(); i++)
{
Node node = nodelist.item(i);
Element Te = (Element) node;
listStatusDetails.add(Te.getAttribute("StatusDetails"));
NodeList ttLine = Te.getElementsByTagName("Line");
for (int j = 0; j < ttLine.getLength(); j++)
{
Node nNode = ttLine.item(j);
Element eElement = (Element) nNode;
listLineNames.add(eElement.getAttribute("Name"));
}
}
NodeList ttStatus = Te.getElementsByTagName("Status");
for (int j = 0; j < ttStatus.getLength(); j++)
{
Node nNode = ttStatus.item(j);
Element eElement = (Element) nNode;
listLineStatuses.add(eElement.getAttribute("Description"));
}
}
}
So as you can see in the code above, the Status is taken both from Lines and from BranchDisruption.
I want to ignore the on my parsing, so only the Status from Line is parsed.
Any ideas ?
You can use your code and alter it like this:
NodeList ttStatus = Te.getElementsByTagName("Status");
for (int j = 0; j < ttStatus.getLength(); j++)
{
Node nNode = ttStatus.item(j);
if (nNode.getParentNode().getNodeName().equals("LineStatus")) {
Element eElement = (Element) nNode;
listLineStatuses.add(eElement.getAttribute("Description"));
}
}
However the XML you are receiving isn't very nice to work with. An id should always be unique in an XML document and should not be used as a flag for the result. If you can manipulate your provider to change their XML please do.
If you succeed with that you should be able to use getElementById instead which would be both faster and more accurate. The current XML doesn't make this an option though.
i think its better to use xmlparser to parsing xml reponce.its too much easier way rather than this.
This is best demo example for xmlParsing:
reference link
I hope its useful to you.
XPath can be used for get only required statuses:
XPath path = XPathFactory.newInstance().newXPath();
NodeList nl=(NodeList)path.evaluate("LineStatus/Status/#Description", doc, XPathConstants.NODESET);
for (int i = 0; i < nl.getLength(); i++) {
System.out.println(nl.item(i).getNodeValue());
}
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 want to read a multi level tags from xml(DOM) using java and the sample xml is : <root>
<subclass>
<subclass>
<subclass>
<name>test1</name>
<address>address1</address>
</subclass>
<name>test2</name>
<address>address2</address>
</subclass>
<name>test3</name>
<address>address3</address>
</subclass>
</root>
How to read <name>test2</name> and <address>address2</address> from the above xml?
I have given a sample code .. but i need to find the values dynamically.
when i am iterating bu using subclass tag, it's giving all the data. just i want to know how to get the specific data like <name>test2</name> and <address>address2</address> .
Below is my java code which is reading the above xml:
NodeList fList = firstWordElement
.getElementsByTagName("root");
for (int i = 0; i < fList.getLength(); i++) {
Node firstFLNode = fList.item(i);
if (firstFLNode.getNodeType() == Node.ELEMENT_NODE) {
Element firstWdElement = (Element) firstFLNode;
NodeList firstWdList = firstWdElement.getElementsByTagName("innerclass");
for (int j = 0; j < firstWdList.getLength(); j++) {
Element firstWd1Element = (Element) firstWdList.item(j);
if (firstWd1Element.getNodeType() == Node.ELEMENT_NODE) {
String InnerName = ParseUtil.getTagValue("name", firstWd1Element);
String InnerFormat = ParseUtil.getTagValue("format", firstWd1Element);
String InnerDescription = ParseUtil.getTagValue("description", firstWd1Element);
NodeList innerClassList = firstWd1Element.getElementsByTagName("subclass");
for (int k = 0; k < innerClassList.getLength(); k++) {
Element subClassElement = (Element) innerClassList
.item(k);
if (subClassElement.getNodeType() == Node.ELEMENT_NODE) {
String InnerSubName = ParseUtil.getTagValue("name", subClassElement);
System.out.println("Innername==="+ InnerSubName);
String InnerSubFormat = ParseUtil.getTagValue("format", subClassElement);
System.out.println("Innerformat==="+ InnerSubFormat);
String InnerSubDescription = ParseUtil.getTagValue("description", subClassElement);
System.out.println("Innerdescription==="+ InnerSubDescription);
}
}
}
}
}
}
A quick way to do this is by using XPath queries. Check out these tutorials:
http://www.ibm.com/developerworks/library/x-javaxpathapi/index.html
http://www.javabeat.net/2009/03/how-to-query-xml-using-xpath/
Traditionally you have to iterate trough the nodes, usually done by creating a NodeList with getChildren() from the parent node. If you only want the test2 -node you have to perform some sort of comparison - you can't jump straight to the second node. That is to say you can, but that wont make a very robust or scale able solution.
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());
}
}
}
}