Tratamiento de ficheros XML con la API DOM de Java
31 de Octubre del 2016
Hola a todos, después de hablaros sobre cómo gestionar ficheros en Java hoy escribiré un post de cómo podemos tratar (lectura y escritura) ficheros XML a través del API DOM.
Como viene siendo habitual primero un pequeño repaso a los términos que utilizaremos a lo largo del post.
XML (eXtensible Markup Language) y DOM (Document Object Model)
XML es un lenguaje de marcas muy estandarizado utilizado para almacenar e intercambiar datos de forma legible, caracterizado por estructurarse a través de etiquetas.
Ejemplo de archivo XML que utilizaremos en este post:
<concesionario>
<coche id="1">
<marca>Renault</marca>
<modelo>Megane</modelo>
<cilindrada>1.5</cilindrada>
</coche>
<coche id="2">
<marca>Seat</marca>
<modelo>León</modelo>
<cilindrada>1.6</cilindrada>
</coche>
<coche id="3">
<marca>Suzuki</marca>
<modelo>Vitara</modelo>
<cilindrada>1.9</cilindrada>
</coche>
</concesionario>
Por otro lado tenemos DOM, es un modelo (independiente del lenguaje) utilizadas para el tratamiento de estos ficheros a la que podemos añadir SAX, JDOM o XOM. Este parseador genera un árbol de objetos llamados nodos que representan cada etiqueta del documento XML, estos nodos pueden ser de muchos tipos: documentos, elementos, atributos, etc, que se relacionan entre sí mediante relaciones padre-hijo.
Lectura de un archivo XML
A la hora de leer un archivo XML a través de DOM debemos instanciar una serie de clases antes de poder tratar el fichero. Primero utilizaremos la conocida clase File para cargar nuestro fichero.
File file = new File("coches.xml");
Posteriormente y ya dentro de un try/catch (para tratar los excepciones) parsearemos el fichero con estas clases: DocumentBuilderFactory, DocumentBuilder y Document.
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 coches.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("coche");
System.out.println("Número de coches: " + nList.getLength());
Una vez tenemos almacenados los datos del nodo “coche” 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("\nCoche id: " + eElement.getAttribute("id"));
System.out.println("Marca: "
+ eElement.getElementsByTagName("marca").item(0).getTextContent());
System.out.println("Modelo: "
+ eElement.getElementsByTagName("modelo").item(0).getTextContent());
System.out.println("Cilindrada: "
+ eElement.getElementsByTagName("cilindrada").item(0).getTextContent());
}
}
Nos mostraría por consola:
Elemento Raiz: concesionario
Número de coches: 3
Coche id: 1
Marca: Renault
Modelo: Megane
Cilindrada: 1.5
Coche id: 2
Marca: Seat
Modelo: León
Cilindrada: 1.6
Coche id: 3
Marca: Suzuki
Modelo: Vitara
Cilindrada: 1.9
Si no conocemos la estructura podemos utilizar el código de más abajo para leer el archivo XML.
NodeList nList = doc.getElementsByTagName("coche");
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 archivo 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("ejercicio3.xml"));
transformer.transform(source, result);
} catch(Exception e) {
e.printStackTrace();
}
Un ejemplo de como podríamos almacenar los datos de cada nodo antes de escribirlos en un archivo XML podría ser a través de una clase en la que cada atributo sería uno de los elementos del nodo, con esto podríamos crear un array o Arraylist en el que cada posición fuese una instancia con los valores de cada nodo dentro de la estructura del XML.
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(' ', '_');
}
}
Lo instanciariamos de esta forma:
Coche coche = new Coche("Seat", "León", "1.5");
Finalizado este post tan solo queda recordar que mi correo iam@jmoral.es y mi Twitter @owniz están abiertos a todo el mundo para que podáis comentarme cualquier duda o corrección.
Un saludo. ツ