Null pointer when reading XML in Java - java

I am trying to get the all the authors from my xml file in jave here is the xml code
<?xml version="1.0"?>
<map>
<authors>
<author>testasdas</author>
<author>Test</author>
</authors>
</map>
Here is the code I'm using in Java
public static List<String> getAuthors(Document doc) throws Exception {
List<String> authors = new ArrayList<String>();
Element ed = doc.getDocumentElement();
if (notExists(ed, "authors")) throw new Exception("No authors found");
Node coreNode = doc.getElementsByTagName("authors").item(0);
if (coreNode.getNodeType() == Node.ELEMENT_NODE) {
Element coreElement = (Element) coreNode;
NodeList cores = coreElement.getChildNodes();
for (int i = 0; i < cores.getLength(); i++) {
Node node = cores.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) node;
String author = e.getElementsByTagName("author").item(i).getTextContent();
Bukkit.getServer().broadcastMessage("here");
authors.add(author);
}
}
}
return authors;
}
I am getting a java.lang.NullPointerException error when I try run the code but I'm not sure why.
09.04 17:05:24 [Server] SEVERE at com.dcsoft.arenagames.map.XMLHandler.getMapData(XMLHandler.java:42)
09.04 17:05:24 [Server] SEVERE at com.dcsoft.arenagames.map.XMLHandler.getAuthors(XMLHandler.java:73)
09.04 17:05:24 [Server] SEVERE java.lang.NullPointerException

The problem is that your code is indexing the <author> nodelist using i, which counts all children of the <authors> tag, some of which are not <author> elements. When item(i) returns null, you get a NPE when you try to call getTextContent(). You also don't need to do all that navigation (which looks kind of suspicious, and is certainly confusing). Try this instead:
public static List<String> getAuthors(Document doc) throws Exception {
List<String> authors = new ArrayList<String>();
NodeList authorNodes = doc.getElementsByTagName("author");
for (int i = 0; i < authorNodes.getLength(); i++) {
String author = authorNodes.item(i).getTextContent();
Bukkit.getServer().broadcastMessage("here");
authors.add(author);
}
return authors;
}

To find the cause of a java.lang.NullPointerException put a breakpoint on the line the exception occurred at, 73 in this case and investigate the variables on that line.
My guess is that in you line of code:
String author = e.getElementsByTagName("author").item(i).getTextContent()
the variable e is the author element and hence why e.getElementsByTagName("author") returns a null.

Related

Java: Get sum of child node values in a nested xml file

I need to make a program which outputs the price of a specific element in an xml file.
The xml file looks like this:
<list name="root">
<book name="B1" price="30" isbn="123"/>
<list name="L1">
<book name="B2" price="20" isbn="234"/>
<list name="L2">
<cd name="C1" price="15"/>
<cd name="C2" price="5"/>
<book name="B3" price="10" isbn="345"/>
</list>
<cd name="C3" price="15"/>
<book name="B4" price="60" isbn="456"/>
</list>
</list>
My program should output something like this:
getPrice(B1) = 30;
getPrice(L1) = B2+L2+C3+B4 = 125 ...
My idea is to store the names and values in a hashmap, and then get the values from it. But, I have troubles getting the price for the nested lists. The program should work for different xml files as well. Only the types (cd, book and list) will be the same.
Here is my code so far:
public class ManageList implements Assignment7 {
private HashMap<String, Double> data = new HashMap<String, Double>();
#Override
public void loadXml(File input) throws Exception {
// given in the readme
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// get filename => absolute path
String filename = input.getAbsolutePath();
Document doc = db.parse(new File(filename));
// Normalize the XML Structure
doc.getDocumentElement().normalize();
// get the root element from XML document
// Element root = doc.getDocumentElement();
// ####################################
// acces elements and their attributes and store it in a hashmap
// ####################################
NodeList nl = doc.getElementsByTagName("*");
storeNodes(nl);
//System.out.println(Arrays.asList(data));
}
#Override
public Optional<Double> getPrice(String item) {
return null;
}
public void storeNodes(NodeList nl) {
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
int type = n.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element e = (Element) n;
if (e.getTagName() == "book" || e.getTagName() == "cd") {
data.put(e.getAttribute("name"), Double.parseDouble(e.getAttribute("price")));
}
if (e.getTagName() == "list" && n.hasChildNodes()) {
String name = e.getAttribute("name");
//here i get a NumberFormatException
//data.put(name, Double.parseDouble(e.getAttribute("price")));
//just to show output
data.put(name, 0.0);
}
storeNodes(n.getChildNodes());
}
}
}
Hashmap output:
[{B2=20.0, C3=15.0, B3=10.0, B4=60.0, L1=0.0, L2=0.0, root=0.0, C1=15.0, B1=30.0, C2=5.0}]
How can I get the values for the nested Lists?
Thank you!
Since list contains sub attributes, looping from nList.getLength()-1 to 0 will avoid so many problems.
For list we need values(prices) of sub attributes book and cd. So looping from last to first will help us in storing the values of sub attributes in data as a prior step.
Now, For us to get total price of list, we iterate all over NodeList of books and cd.
we sum up all the values which makes the price of the list.
Below is the code if (e.getTagName() == "list" && n.hasChildNodes(),
NodeList books = e.getElementsByTagName("book");
NodeList cd = e.getElementsByTagName("cd");
System.out.println(books.getLength());
System.out.println(cd.getLength());
double listPrice = 0;
for(int i=0;i<books.getLength();i++) {
Node t = books.item(i);
Element e1 = (Element)t;
/**This can be reduced if we loop from nList.getLength()-1 to 0, Since the data already exists in data.
//if (!data.containsKey(e1.getAttribute("name"))){
// data.put(e1.getAttribute("name"),Double.parseDouble(e1.getAttribute("price")));
//
//}
*/
listPrice += Double.parseDouble(e1.getAttribute("price"));
}
for(int i=0;i<cd.getLength();i++){
Node t = cd.item(i);
Element e1 = (Element)t;
listPrice += Double.parseDouble(e1.getAttribute("price"));
}
for any doubts - comment.
Thanks.

Get value of element in xml - always returning null

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.

Retrieving different child elements xml

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)

Getting Element (not Node) below root in Java DOM (XML parser)

I need to get the tag of an element right below the root, but DOM seems only to offer methods getting child nodes (not elements) and you cant cast from one to the other.
http://ideone.com/SUjRmn
#Override
public void loadXml(String filepath) throws Exception {
File f = new File(filepath);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
try {
doc = db.parse(f);
} catch (SAXException | IOException | NullPointerException e) {
e.printStackTrace();
}
Element root = doc.getDocumentElement();
Node firstChild = root.getFirstChild();
String tag = firstChild.getNodeName();
//here is the problem. I can't cast from Node to Element and Node
//stores only an int value, not the name of the object I want to restore
ShapeDrawer drawable = null;
switch (tag) {
case "scribble":
drawable = new ScribbleDrawer();
...
From the class to restore:
#Override
public void setValues(Element root) {
NodeList nodelist = null;
nodelist = root.getElementsByTagName("color");
colorManager.setColor((nodelist.item(0).getTextContent()));
this.color = colorManager.getCurrentColor();
System.out.println(color.toString());
nodelist = root.getElementsByTagName("pressx");
pressx = Integer.parseInt(nodelist.item(0).getTextContent());
System.out.println(pressx);
nodelist = root.getElementsByTagName("pressy");
pressy = Integer.parseInt(nodelist.item(0).getTextContent());
System.out.println(pressy);
nodelist = root.getElementsByTagName("lastx");
lastx = Integer.parseInt(nodelist.item(0).getTextContent());
nodelist = root.getElementsByTagName("lasty");
lasty = Integer.parseInt(nodelist.item(0).getTextContent());
}
public void toDOM(Document doc, Element root) {
System.out.println("ScribbleDrawer being saved");
Element shapeBranch = doc.createElement("scribble");
Attr attr1 = doc.createAttribute("hashcode");
attr1.setValue(((Integer) this.hashCode()).toString());
shapeBranch.setAttributeNode(attr1);
root.appendChild(shapeBranch);
Element eColor = doc.createElement("color");
eColor.setTextContent(colorManager.namedColorToString(color));
shapeBranch.appendChild(eColor);
// creating tree branch
Element press = doc.createElement("press");
Attr attr2 = doc.createAttribute("pressx");
attr2.setValue(((Integer) pressy).toString());
press.setAttributeNode(attr2);
Attr attr3 = doc.createAttribute("pressy");
attr3.setValue(((Integer) pressy).toString());
press.setAttributeNode(attr3);
shapeBranch.appendChild(press);
Element last = doc.createElement("last");
Attr attr4 = doc.createAttribute("lastx");
attr4.setValue(((Integer) lastx).toString());
last.setAttributeNode(attr4);
Attr attr5 = doc.createAttribute("lasty");
attr5.setValue(((Integer) lasty).toString());
last.setAttributeNode(attr5);
shapeBranch.appendChild(last);
}
I know other parsers are easier, but I am almost finished and when it comes to polymorphy JAXB seems to be just as complicated with Option-marshalling etc
EDIT: this is what the xml looks like; instead of "scribble" other tags/polymorphic children are possible which are deserialized from different instance variables (and thus different DOM-trees except for the root)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Drawables>
<scribble hashcode="189680059">
<color>Black</color>
<press pressx="221" pressy="221"/>
<last lastx="368" lasty="219"/>
</scribble>
<scribble hashcode="1215837841">
<color>Black</color>
<press pressx="246" pressy="246"/>
<last lastx="368" lasty="221"/>
</scribble>
If your node is an Element, you can cast it from node to element. But your first child might also be a text node, which can't be cast, of course. You have to test the nodes for their NodeType before casting.
If your XML is not using namespaces, you can use a method like this one to extract your child elements. It receives a list of nodes, test each one and returns a list containing only the elements:
public static List getChildren(Element element) {
List<Element> elements = new ArrayList<>();
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
elements.add((Element) node);
}
}
return elements;
}
An alternative is to use an API which already includes such utility methods, like DOM4J, or JDOM.

how to read a specific element from multi level tags of xml(DOM) by using java

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.

Categories