Trabajo con ficheros XML con DOM

XML es un metalenguaje que nos permite jerarquizar y estructurar la información así como describir los contenidos dentro del propio documento. Son ficheros de texto con información almacenada de forma secuancial y estructurada. Las marcas especiales que nos permiten delimitar el contenido  y la estructura son los símbolos de “>” y “<“. Cada marca tiene un nombre y puede tner 0 o más atributos.

<?xml version="1.0">
<Empleados>
  <empleado id="1">
    <apellido>Martinez</apellido>
    <dep>10</dep>
    <salario>1000.33</slario>
  </empleado>
  <empleado id="2">
    <apellido>Garcia</apellido>
    <dep>11</dep>
    <salario>2000.34</slario>
  </empleado>
  <empleado id="3">
    <apellido>Navarro</apellido>
    <dep>10</dep>
    <salario>2222.33</slario>
  </empleado>
</Empleados>

Para leer los ficherosXML y acceder a su contenido y estructura, se utiliza el procesador de XML o parser. Algunos de los procesadores más utilizados son:

  • DOM = Modelo de Objetos de Documentos
  • SAX = API Simple para XML

DOM: almacena toda la estructura del documento en forma de árbol. Necesita más recursos y memoria.

SAX: apenas consume memoria, pero impide tener una visión global del documento. Lee de forma secuencial y produce una secuencia de eventos (inicio/fin de documento; inicio/fin de etiqueta; etc.) donde cada evento invocará un método definido por el programador.

ACCESO A FICHEROS XML CON DOM

Paquetes necesarios:

Estas clases e interfaces ofrecen métodos para cargar documentos desde una fuente de datos (File, InputStream, etc.)

Pero hay dos clases fundamentales:

Los programas Java que utilicen DOM necesitan principalmente estas interfaces:

  • Document: objeto que equivale a un ejemplar de un documento XML, permite crear nuevos nodos.
  • Element: Cada elemento del documento XML tiene un equivalente en un objeto de este tipo. Expone propiedades y métodos para manipular los elementos del documento y sus atributos.
  • Node: Representa a cualquier nodo del documento.
  • NodeList: Contiene una lista con los nodos hijos de un nodo.
  • Attr: Permite acceder a los atributos de un nodo.
  • Text: Son los datos carácter de un elemento.
  • CharacterData: Representa a los datos carácter del documento.
  • DocumentType: Proporciona información contenida en la etiqueta <!DOCTYPE>.

Lectura de un fichero XML

...
File file = new File("empleados.xml");
...
try {
  DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
  Document doc = dBuilder.parse(file);
} catch(Exception e) {
  e.printStackTrace();
}

Una vez hecho todo esto ya podremos leer el archivo empleados.xml además de usar otros métodos como los ejemplos de aquí abajo.

Método Descripción
getDocumentElement() Accede al nodo raíz del documento
normalize() Elimina nodos vacíos y combina adyacentes en caso de que los hubiera
...
// estos métodos podemos usarlos combinados para normalizar el archivo XML
doc.getDocumentElement().normalize();
...

Siguiendo dentro del try/catch podemos utilizar la clase NodeList para almacenar el elemento que le indicaremos como parámetro.

// almacenamos los nodos para luego mostrar la
// cantidad de ellos con el método getLength()
NodeList nList = doc.getElementsByTagName("empleado");
System.out.println("Número de empleados: " + nList.getLength());

Una vez tenemos almacenados los datos del nodo “empleado” podemos leer su contenido teniendo en cuenta que este código depende de que conozcamos la estructura y etiquetas utilizadas.

for(int temp = 0; temp < nList.getLength(); temp++) {
  Node nNode = nList.item(temp);

  if(nNode.getNodeType() == Node.ELEMENT_NODE) {
    Element eElement = (Element) nNode;

    System.out.println("\nEmpleado id: " + eElement.getAttribute("id"));
    System.out.println("Apellido: "
                + eElement.getElementsByTagName("apellido").item(0).getTextContent());
    System.out.println("Departamento: "
                + eElement.getElementsByTagName("dep").item(0).getTextContent());
    System.out.println("Salario: "
                + eElement.getElementsByTagName("salario").item(0).getTextContent());
  }
}

Si no conocemos la estructura podemos utilizar el código de más abajo para leer el archivo XML.

NodeList nList = doc.getElementsByTagName("empleado");

for (int i = 0; i < nList.getLength(); i++) {
  Node node = nList.item(i);

  if (node.getNodeType() == Node.ELEMENT_NODE) {
    Element eElement = (Element) node;

    if(eElement.hasChildNodes()) {
      NodeList nl = node.getChildNodes();
      for(int j=0; j<nl.getLength(); j++) {
        Node nd = nl.item(j);
        System.out.println(nd.getTextContent());
      }
    }
  }
}

Escritura de un fichero XML

Si quisiéramos escribir un archivo XML siguiendo la misma estructura del concesionario deberíamos instanciar las clases DocumentBuilderFactory, DocumentBuilder y Document, definir toda la estructura del archivo (siempre dentro de un bloque try/catch) y por último instanciar las clases TransformerFactory, Transformer, DOMSource y StreamResult para crear el archivo.

try {
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  DocumentBuilder db = dbf.newDocumentBuilder();
  Document doc = db.newDocument();

  // definimos el elemento raíz del documento
  Element eRaiz = doc.createElement("concesionario");
  doc.appendChild(eRaiz);

  // definimos el nodo que contendrá los elementos
  Element eCoche = doc.createElement("coche");
  eRaiz.appendChild(eCoche);

  // atributo para el nodo coche
  Attr attr = doc.createAttribute("id");
  attr.setValue("1");
  eCoche.setAttributeNode(attr);

  // definimos cada uno de los elementos y le asignamos un valor
  Element eMarca = doc.createElement("marca");
  eMarca.appendChild(doc.createTextNode("Renault"));
  eCoche.appendChild(eMarca);

  Element eModelo = doc.createElement("modelo");
  eModelo.appendChild(doc.createTextNode("Megano"));
  eCoche.appendChild(eModelo);

  Element eCilindrada = doc.createElement("cilindrada");
  eCilindrada.appendChild(doc.createTextNode("1.5"));
  eCoche.appendChild(eCilindrada);

  // clases necesarias finalizar la creación del archivo XML
  TransformerFactory transformerFactory = TransformerFactory.newInstance();
  Transformer transformer = transformerFactory.newTransformer();
  DOMSource source = new DOMSource(doc);
  StreamResult result = new StreamResult(new File("coches.xml"));

  transformer.transform(source, result);
} catch(Exception e) {
  e.printStackTrace();
}

Utilizando objetos y Array

public class Coche {
  private String marca;
  private String modelo;
  private String cilindrada;

  public Coches() {
    marca = "Renault";
    modelo = "Megane";
    cilindrada = "1.5";
  }

  public Coches(String nombre, String creador, String ciudad) {
    this.marca = nombre;
    this.modelo = creador;
    this.cilindrada = ciudad;
  }

  @Override
  public String toString() {
    return this.marca.replace(' ', '_') + " " +
           this.modelo.replace(' ', '_') + " " +
           this.cilindrada.replace(' ', '_');
  }
}

Y la instacia sería:

...
Coche coche = new Coche("Seat", "León", "1.5");
...

 

Utilizando el fichero “AleatorioEmple.dat” utilizado en ejercicios anteriores vamos realizar un programa que lea los empleados creados en dicho archivo y los guarde en un fichero XML.

Librería  jar_files

package pkgCrearEmpleadoXml;

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import java.io.*;

public class CrearEmpleadoXml {
  public static void main(String[] args) throws IOException{
    File f = new File("C:\\Users\\Victor\\Documents\\ADA\\T0\\AleatorioEmple\\lib\\FichData.dat");
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    int id, departamento;
    float salario;
    String apellidoS;
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      DOMImplementation implementation = builder.getDOMImplementation();
      Document document = implementation.createDocument(null, "Empleados", null);
      document.setXmlVersion("1.0");
      for(;;) {
        id = raf.readInt();
        apellidoS = raf.readUTF();
        departamento = raf.readInt();
        salario = raf.readFloat();
        System.out.println("ID: " + id + "; Apellido: " + apellidoS +
            "; Departamento: " + departamento + "; Salario: " + salario);
        Element raiz = document.createElement("empleado");
        document.getDocumentElement().appendChild(raiz);
        crearElemento("ID",Integer.toString(id),raiz,document); // añadir ID
        crearElemento("apellido",apellidoS.trim(),raiz,document); // añadir apellido
        crearElemento("departamento",Integer.toString(departamento),raiz,document); // añadir DEP
        crearElemento("salario",Float.toString(salario),raiz,document); // añadir salario
        if (raf.getFilePointer() >= raf.length()) break;
      }
      Source source = new DOMSource(document);
      Result result = new StreamResult (new File("lib\\Empleados.xml"));
      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      transformer.transform(source,result);
    }catch(EOFException eofe) {
      System.out.println("Error End Of File: " + eofe.getMessage());
    }catch(IOException e) {
      System.out.println("Error IO: " + e.getMessage());
    }catch(TransformerConfigurationException tce) {
      System.out.println("Error Transformer Configuration: " + tce.getMessage());
    }catch(TransformerException te) {
      System.out.println("Error Transformer: " + te.getMessage());
    }catch(ParserConfigurationException pce) {
      System.out.println("Error Parser Configuration: " + pce.getMessage());
    }finally {
      raf.close();
    }

  }
  static void crearElemento(String datoEmpleado, String valor, Element raiz, Document document) {
    Element elem = document.createElement (datoEmpleado); //creamos hijo
    Text text = document.createTextNode(valor); // damos valor al campo
    raiz.appendChild(elem); //pegamos el elemento hijo a la raiz
    elem.appendChild(text); //pegamos el valor
  }
}

Sube ambos ejercicios a tu repositorio GIT en 2dam.fp.edu.es

No olvides crear el fichero README.md y explicar en el mismo que hace tu aplicación y como lo hace.

Ejercicio 10. La lectura de este archivo XML:

  • Crear una instacia de DocumentBuilderFactory
    • Cargar el documento con el método parser();
      Document document = builder.parse(new File(“Empleados.xml”));
  • Obtener la lista de nodos con el nombre empleado de todo el documento
    • NodeList empleados = document.getElementByTagName(“empleado”);
  • Luego con un bucle recorremos la lista
  • Para cada nodo obtenemos etiquetas y valores utilizando la función getNodo();

Ejercicio 11. A partir del fichero de objetos Persona crea un XML usando DOM