Because I get Nullpointerexception when I save an attribute of a node

1

I am trying to show an XML file on the screen through the DOM, but after converting the aforementioned file, when I want to save the data of each node in a array I get the error:

    Exception in thread "main" java.lang.NullPointerException
    at gestionardom.Metodos.procesarLibro(Metodos.java:103)
    at gestionardom.Metodos.recorreDOMyMuestraPOrPantalla(Metodos.java:78)
    at gestionardom.GestionarDOM.main(GestionarDOM.java:36)
    C:\Users\Victor\AppData\Local\NetBeans\Cache.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)

My question is: when using nodo.getAttributes().item(0).getNodeValue(); it gives me as a value null if it should return the value of the indicated node?

metodos.java

package gestionardom;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

/**
 *
 * @author Victor
 */
public class Metodos {

    private Document doc; //Almacena del DOM del XML

    public int convertir_XML_DOM(File fichero){//COPIAR Y PEGAR ALWAYS
        // Creo un objeto DocumentBuilderFactory
        // Analiza un fichero XML para posteriormente generar el árbol DOM
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        //Opciones: Sin espacios y sin comentarios
        factory.setIgnoringComments(true);
        factory.setIgnoringElementContentWhitespace(true);

        //Creo un objeto DocumentBuilder
        DocumentBuilder builder = null;


        try {
            //Cargo la estructura de árbol DOM con las opciones señaladas anteriormente
            builder = factory.newDocumentBuilder();
            try {
                //Interpreto el XML y genero el DOM correspondiente
                doc = builder.parse(fichero);
                return 0;
            } catch (SAXException e) {
                e.printStackTrace();
                return -1;
            } catch (IOException e) {
                e.printStackTrace();
               return -1;
            }

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
            return -1;
        }

    }


    public String recorreDOMyMuestraPOrPantalla(){
        String salida = "";
        String[] datos_nodo = new String[3];

        Node nodo; //Nodo del árbol DOM
        Node raiz = doc.getFirstChild(); //Obtiene la raíz <libros>

        NodeList nodelist = raiz.getChildNodes(); //Obtiene los hijos del raíz <libro>

        //Recorremos los nodos, en este caso 4 <libro>
        for(int i=0; i<nodelist.getLength();i++){
            nodo = nodelist.item(i); //Almaceno el primer nodo, es decir, el primer <libro>


           datos_nodo = procesarLibro(nodo);


            if(nodo.getNodeType() == Node.ELEMENT_NODE){ //Comprobamos que sea un elemento
               salida = salida + "\n " +"Publicado en: " + datos_nodo[0]; //Nodo final
                salida = salida + "\n " +"El autor es: " + datos_nodo[1]; //Nodo final
                salida = salida + "\n " +"El título es: " + datos_nodo[2]; //Nodo final
                salida = salida + "\n" +"------------------------" + "\n";
            }
        }

        return salida;
    }



    public String[] procesarLibro(Node nodo){
        String datos[] = new String[3];
        //datos[0] --> Publicado en
        //datos[1] --> Titulo
        //datos[2] --> Autor

        Node temporal = null;
        int contador = 1;

        datos[0] = nodo.getAttributes().item(0).getNodeValue();

        NodeList nodos = nodo.getChildNodes();
        for(int i=0; i<nodos.getLength(); i++){
            temporal  = nodos.item(i);

            if(temporal.getNodeType() == Node.ELEMENT_NODE){
                datos[contador]  = temporal.getChildNodes().item(0).getNodeValue();
                contador++;
            }
        }

        return datos;
    }

}

ManageDOM.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package gestionardom;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
public class GestionarDOM {

    /**
     * @param args the command line arguments
     */




    public static void main(String[] args) {

      File archivo = new File ("C:\libros.xml");

      Metodos metodo= new Metodos();

      if(metodo.convertir_XML_DOM(archivo)==0)
      {

          metodo.recorreDOMyMuestraPOrPantalla();

      }
      else{
          System.out.print("No es posible leer el fichero");
      }




    }




}

XML file

books.xml

<?xml version="1.0" encoding="UTF-8"?>
<Libros>
 <Libro publicado_en="1840">
   <Titulo>El Capote</Titulo>
   <Autor>Nikolai Gogol</Autor>
 </Libro>
 <Libro publicado_en="2008">
   <Titulo>El Sanador de Caballos</Titulo>
   <Autor>Gonzalo Giner</Autor>
 </Libro>
 <Libro publicado_en="1981">
   <Titulo>El Nombre de la Rosa</Titulo>
   <Autor>Umberto Eco</Autor>
 </Libro>
 <Libro publicado_en="1982">
   <Titulo>El libro de la selva</Titulo>
   <Autor>Carmen</Autor>
 </Libro>
</Libros>
    
asked by victor96 23.11.2018 в 14:42
source

2 answers

2

The problem is that some no nodes are type ELEMENT_NODE , but not TEXT_NODE which contain the value of line break ( \n ) and those types of nodes do not contain attributes. I think that answers your question.

Now I'll leave you the inconveniences that you have in your code, how to solve or validate them, and at the end I leave some tests that you can perform to see why your exception.

Let's start:

Your first problem is that within the recorreDOMyMuestraPOrPantalla method, specifically within the for , you are sending a call procesarLibro to then validate if the current node is a ELEMENT_NODE . It would not be better to validate the node type first and then execute procesarLibro .

It would stay like this, and with this it will work for you:

if (nodo.getNodeType() == Node.ELEMENT_NODE) { //Comprobamos que sea un elemento
    datos_nodo = procesarLibro(nodo);
    salida = salida + "\n " + "Publicado en: " + datos_nodo[0]; //Nodo final
    salida = salida + "\n " + "El autor es: " + datos_nodo[1]; //Nodo final
    salida = salida + "\n " + "El título es: " + datos_nodo[2]; //Nodo final
    salida = salida + "\n" + "------------------------" + "\n";
}

Second problem, although the node type is now validated, you must also validate within the procesarLibro method if the node it is processing contains attributes.

// puedes validar con el metodo hasAttributes
if(!nodo.hasAttributes()) {
    return datos;
}

datos[0] = nodo.getAttributes().item(0).getNodeValue();

can also be used:

// verificando si el metodo getAttributes devuleve algun valor
if(nodo.getAttributes() == null) {
    return datos;
}

datos[0] = nodo.getAttributes().item(0).getNodeValue();

I recommend using hasAttributes() . With these two modifications ensure always process the nodes type ELEMENT_NODE and that the nodes have attributes.

  

Now the question, because before those validations throws that error.

To answer that, let's go back to the method recorreDOMyMuestraPOrPantalla and add the following lines of code within the for , to print the basic information of the node:

for (int i = 0; i < nodelist.getLength(); i++) {
    nodo = nodelist.item(i);

    // imprimiendo informacion del nodo
    System.out.println(String.format("NodeName: %s\nNodeType: %s\nTextContent: %s",
            nodo.getNodeName(),
            nodo.getNodeType(),
            nodo.getTextContent()));

    if (nodo.getNodeType() == Node.ELEMENT_NODE) { //Comprobamos que sea un elemento
        datos_nodo = procesarLibro(nodo);
        salida = salida + "\n " + "Publicado en: " + datos_nodo[0]; //Nodo final
        salida = salida + "\n " + "El autor es: " + datos_nodo[1]; //Nodo final
        salida = salida + "\n " + "El título es: " + datos_nodo[2]; //Nodo final
        salida = salida + "\n" + "------------------------" + "\n";
    }
}

With this we print the name, type and content of the current node. With the xml that you provided the output would be this:

NodeName: #text
NodeType: 3
TextContent: 

NodeName: Libro
NodeType: 1
TextContent: 
   El Capote
   Nikolai Gogol

NodeName: #text
NodeType: 3
TextContent: 

NodeName: Libro
NodeType: 1
TextContent: 
   El Sanador de Caballos
   Gonzalo Giner

NodeName: #text
NodeType: 3
TextContent: 

NodeName: Libro
NodeType: 1
TextContent: 
   El Nombre de la Rosa
   Umberto Eco

NodeName: #text
NodeType: 3
TextContent: 

NodeName: Libro
NodeType: 1
TextContent: 
   El libro de la selva
   Carmen

NodeName: #text
NodeType: 3
TextContent: 

As you can see we get 9 nodes and some nodes say #text and the node type is 3 , which is equivalent to TEXT_NODE and not the type ELEMENT_NODE that is the one you want to process.

Here is a small portion of the Node interface code:

public interface Node {
    // NodeType
    public static final short ELEMENT_NODE = 1;
    public static final short TEXT_NODE    = 3;

    ...
}

That's why it throws you an exception, since some nodes that you process are of type text, which do not contain attributes.

  

And because I have those node types if in the xml I do not see them or the e   placed?

Modify the xml, to answer that.

Books.xml modified (all in one line):

<?xml version="1.0" encoding="UTF-8"?><Libros><Libro publicado_en="1840"><Titulo>El Capote</Titulo><Autor>Nikolai Gogol</Autor></Libro><Libro publicado_en="2008"><Titulo>El Sanador de Caballos</Titulo><Autor>Gonzalo Giner</Autor></Libro><Libro publicado_en="1981"><Titulo>El Nombre de la Rosa</Titulo><Autor>Umberto Eco</Autor></Libro><Libro publicado_en="1982"><Titulo>El libro de la selva</Titulo><Autor>Carmen</Autor></Libro></Libros>

Let's run again and we'll see that the output is different:

NodeName: Libro
NodeType: 1
TextContent: El CapoteNikolai Gogol
NodeName: Libro
NodeType: 1
TextContent: El Sanador de CaballosGonzalo Giner
NodeName: Libro
NodeType: 1
TextContent: El Nombre de la RosaUmberto Eco
NodeName: Libro
NodeType: 1
TextContent: El libro de la selvaCarmen

It no longer contains types TEXT_NODE = 3 and TextContent has the information pasted.

Then the reason is that the xml that you are reading also processes the \n (line breaks) as a node and those nodes with line break values ( \n ) do not contain attributes.

  

At the end of your method recorreDOMyMuestraPOrPantalla and procesarLibro   based on the xml that you provided would be like this:

public String recorreDOMyMuestraPOrPantalla() {
    String salida = "";
    String[] datos_nodo = new String[3];

    Node nodo;
    Node raiz = doc.getFirstChild();

    NodeList nodelist = raiz.getChildNodes();

    for (int i = 0; i < nodelist.getLength(); i++) {
        nodo = nodelist.item(i);

        /* Test para obtener informacion de los nodos recorridos
        System.out.println(String.format("NodeName: %s\nNodeType: %s\nTextContent: %s",
                nodo.getNodeName(),
                nodo.getNodeType(),
                nodo.getTextContent()));
         */

        if (nodo.getNodeType() == Node.ELEMENT_NODE) {
            datos_nodo = procesarLibro(nodo);
            salida = salida + "\n " + "Publicado en: " + datos_nodo[0];
            salida = salida + "\n " + "El autor es: " + datos_nodo[1];
            salida = salida + "\n " + "El título es: " + datos_nodo[2];
            salida = salida + "\n" + "------------------------" + "\n";
        }
    }

    return salida;
}

public String[] procesarLibro(Node nodo) {
    String datos[] = new String[3];
    Node temporal = null;
    int contador = 1;

    if (!nodo.hasAttributes()) {
        return datos;
    }

    datos[0] = nodo.getAttributes().item(0).getNodeValue();

    NodeList nodos = nodo.getChildNodes();
    for (int i = 0; i < nodos.getLength(); i++) {
        temporal = nodos.item(i);

        if (temporal.getNodeType() == Node.ELEMENT_NODE) {
            datos[contador] = temporal.getChildNodes().item(0).getNodeValue();
            contador++;
        }
    }

    return datos;
}
    
answered by 23.11.2018 в 18:00
1

There are several possibilities:

1 - node.getAttributes () is null 2 - item (0) is null 3 - getNodeValue () is null

Debug the code to find this out and add conditions to avoid the null pointer exception, such as:

if (node.getAttributes() != null) { ...
    
answered by 23.11.2018 в 15:01