Diferencia entre revisiones de «Prog Tratamientos de documentos XML»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 302: Línea 302:
  
 
* Dado el siguiente archivo XML:
 
* Dado el siguiente archivo XML:
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="xml" enclose="div" highlight="" >
</syntaxhighlight>  
 
 
<?xml version="1.0"?>
 
<?xml version="1.0"?>
 
<company>
 
<company>

Revisión del 14:50 18 abr 2018

Introducción

  • XML viene de Extensible Markup Language.


  • Podéis consultar la historia y uso del XML en este enlace.


  • Uno de los usos del lenguaje XML es el intercambio de información entre sistemas heterogéneos.
La información se transmite en formato texto (normalmente unicode) con una estructura en forma de etiquetas muy parecida a la conocida por todos, HTML.


  • Veamos un ejemplo de fichero XML:
<?xml version="1.0" encoding="UTF-8" ?>
<pedidos num_pedidos="1"  fecha_pedido="10/02/2012">
 <responsable>Angel Fernandez</responsable>
 <pedido>
  <id>1</id>
  <productos num_productos="2">
    <producto>
     <codigo>221</codigo>
     <cantidad>10</cantidad>
    </producto>
    <producto>
     <codigo>231</codigo>
     <cantidad>10</cantidad>
    </producto>
   </productos>
 </pedido>
</pedidos>


  • Para que un documento cumpla el estándar XML tiene que cumplir las siguientes reglas:
  • Debe de tener una cabecera donde se especifica la versión de XML que cumple el documento. También suele aparecer tipo de codificación, normalmente UTF-8 o ISO-8859-1.
  • El documento debe estar estructurado en forma de etiquetas de apertura <etiqueta> y cierre </etiqueta>.
  • Un documento debe de tener al menos una etiqueta de apertura y otra de cierre.
  • Se pueden poner etiquetas que abran y cierren la etiqueta al mismo tiempo de la forma: <etiqueta />. Por ejemplo: <representante nombre="Angel" />
  • El orden de las etiquetas es importante. Se deben cerrar en el orden inverso a como fueron abiertas.
  • Se distingue mayúsculas y minúsculas en la apertura y cierre de etiquetas.
  • Una etiqueta puede llevar uno o más atributos. Por ejemplo: <pedidos num_pedidos="10" fecha_pedido="10/01/2012">
  • No puede haber atributos con el mismo nombre en la misma etiqueta.
  • Todos los atributos deben ir entre comillas dobles.
  • Se pueden añadir comentarios de la forma:
  • Los nombres de las etiquetas y atributos no pueden tener espacios en blanco.



  • En Java, cuando manejamos un documento XML o bien creamos uno nuevo, vamos a tener que recorrer / crear la estructura anterior.
En Java cada elemento de esa estructura recibe un nombre. Así:
  • Las etiquetas de apertura y cierre junto con su contenido se denomina Elements. En element puede tener otros 'element' en su contenido.
  • Los atributos se denominan Attr y sólo pueden existir dentro de element, en la etiqueta de apertura.
  • La información (el texto) que va entre las etiquetas de apertura y cierre se denomina Text.
  • Los comentarios pueden ir en cualquier lugar del documento y se denominan Comment.



Java: Procesando archivos XML

  • Cuando tratemos con documentos XML vamos a diferenciar dos fases:
  • Comprobar que el documento XML esté bien formado en base a las reglas que indicamos en la introducción.
  • Pasar dicho documento a un conjunto de objetos que podamos manejar desde Java. Este formato se denomina DOM (Document Object Model), modelo de objetos. En DOM cada etiqueta es un nodo de una rama de un árbol jerárquico a la que vamos podemos acceder obteniendo su contenido, atributos, nombre,...
  • Tanto el estándar XML como DOM, son estándares propuesto por W3C (World Wide Web Consortium)


  • Por lo tanto vamos a pasar el documento XML en formato texto a un árbol DOM desde donde poder acceder a cada uno de los elementos del documento XML.



Pasando de documento XML a árbol DOM

  • Lo primero que tenemos que hacer es verificar que el documento XML esté bien formado. Para ello se hace uso de un parser.
  • Hay dos tipos parser:
  • Sin validación: Comprueba que el documento esté bien formado de acuerdo a las reglas de sintaxis de XML.
  • Con validación: Además de comprobar que el documento está bien formado, comprueba el documento utilizando un DTD (ya sea interno o externo). Un DTD (Document Type Definition) es un documento en el que se indica cual es la estructura que tiene que tener el documento, sus elementos y atributos.
  • Nosotros vamos a hacer uso de un parser sin validación que además va a ser compatible con el modelo de objeto de documento (DOM) de XML


  • Vamos a hacer uso de las siguientes clases:


  • Los pasos a seguir son los siguientes:
 1     public static void main(String[] arg){
 2         
 3         try {
 4             // Construimos nuestro DocumentBuilder
 5             DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 6             // Procesamos el fichero XML y obtenemos nuestro objeto Document
 7             Document doc = documentBuilder.parse(new File("/tmp/fichero.xml"));
 8 
 9 
10 
11         } catch (FileNotFoundException ex) {
12             Logger.getLogger(Principal.class.getName()).log(Level.SEVERE, null, ex);
13         } catch (SAXException ex) {
14             System.out.println("Fichero no pasa validación");
15             Logger.getLogger(Principal.class.getName()).log(Level.SEVERE, null, ex);
16         } catch (IOException ex) {
17             Logger.getLogger(Principal.class.getName()).log(Level.SEVERE, null, ex);
18         } catch (ParserConfigurationException ex) {
19             Logger.getLogger(Principal.class.getName()).log(Level.SEVERE, null, ex);
20         }
21         
22         
23     }
  • Línea 7: El método parse está sobrecargado y podemos enviar un InputStream.
  • Las excepciones son las conocidas y dos nuevas. La principal es SAXException, que se lanzará en caso de que el fichero esté mal formado (no cumpla con las reglas de XML vistas en el punto inicial).




Manipulando un árbol DOM

  • Como comentamos anteriormente, cada par de etiquetas del archivo XML conforman un Element.


Obteniendo el elemento raíz

  • Para obtener el elemento raíz (nodo raíz) del documento (recordar que obligatoriamente debe existir para cumplir con el estándar XML) llamaremos al método getDocumentElement.
1             DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
2             Document doc = documentBuilder.parse(new File("/home/clase/Documentos/documento.xml"));
3             
4             Element raiz = doc.getDocumentElement();


  • Podemos saber el nombre de la etiqueta asociado a un elemento con el método getTagName() que devuelve un String.


Accediendo a los atributos de un Element

  • Una vez en dicho elemento podemos recuperar sus atributos (si tiene) de dos formas:
  • getAttribute(java.lang.String): Se le envía como parámetro el nombre del atributo y devuelve su valor siempre en String. En caso de que no exista el atributo, devuelve la cadena vacía.
  • getAttributeNode(java.lang.String): Se le envía como parámetro el nombre del atributo y devuelve un objeto de la clase Attr la cual dispone de métodos para obtener el nombre del atributo, obtener su valor, modificarlo,...Devuelve null en caso de que el atributo no exista.



Veamos un ejemplo (no se comprueba que los atributos existan):
 1             Element raiz = doc.getDocumentElement();
 2             
 3             
 4             System.out.println("Ejemplo de acceso a los atributos de un Element utilizando el método getAttribute");
 5             int numPedidos = Integer.parseInt(raiz.getAttribute("num_pedidos"));
 6             System.out.printf("Número de pedidos:%d%n",numPedidos);
 7             System.out.println("Fecha del pedido:" + raiz.getAttribute("fecha_pedido"));
 8             
 9             // Podemos pasar la fecha a Date por si queremos hacer operaciones sobre ella
10             DateFormat format = new SimpleDateFormat("dd-MM-yyyy",new Locale("es_ES"));
11             Date date = format.parse(raiz.getAttribute("fecha_pedido"));
12             System.out.printf("Fecha del pedido:%s%n",date);
13             
14             System.out.println("\nEjemplo de acceso a los atributos de un Element utilizando el método getAttributeNode");
15             Attr atribNumPedidos = raiz.getAttributeNode("num_pedidos");
16             System.out.printf("El nombre del atributo es %s y su valor es %s%n",atribNumPedidos.getName(),atribNumPedidos.getValue());
17             
18             Attr atribFechaPedido = raiz.getAttributeNode("fecha_pedido");
19             System.out.printf("El nombre del atributo es %s y su valor es %s%n",atribFechaPedido.getName(),atribNumPedidos.getValue());


Accediendo a los nodos dentro del árbol DOM

  • Podemos 'navegar' por el árbol DOM utilizando los métodos que se encuentran en la interface Node y que implementa la clase Element.
Entre ellos tenemos:
Todos estos métodos devuelve un objeto de la clase Node o un objeto de la clase NodeList (que viene a ser como un conjunto de Nodes, lo veremos después).
Un objeto de la clase Node puede representar entre otros:
Podemos averiguar a qué tipo pertenece llamando al método getNodeType() de la clase Node.
IMPORTANTE: En XML los saltos de línea del documento se transforman en espacios en blanco que también constituyen 'nodos' dentro del árbol (de tipo TEXT_NODE). Tendrás que tenerlos en cuenta para la navegación.


Veamos un ejemplo:
 1             Element raiz = doc.getDocumentElement();
 2             Node nodoResponsable = raiz.getFirstChild().getNextSibling();  // El primer hijo del raíz es el espacio en blanco del salto de línea
 3             if (nodoResponsable.getNodeType()==Node.ELEMENT_NODE){
 4                 System.out.println("Es un elemento del archivo XML");
 5                 System.out.println("Nombre de la etiqueta:" + nodoResponsable.getNodeName());
 6                 
 7                 Node textoResponsable = nodoResponsable.getFirstChild();
 8                 System.out.println("Texto de la etiqueta:" + textoResponsable.getNodeValue());
 9 
10                 System.out.println("Texto de la etiqueta:" + nodoResponsable.getTextContent());  // Otra forma de obtener el texto asociado a una etiqueta
11 
12             }


Ejercicio propuesto: Navega manualmente hasta <productos> y obtén el valor del atributo número de productos.
Después navega hasta el primer producto y obtén su código y cantidad.


Se le debe pasar el nombre de la 'etiqueta' a buscar y devolverá el conjunto de nodos del árbol que tenga esa etiqueta, en forma de objeto de la clase Nodelist.
Después tendremos que recorrer ese conjunto de nodos con un bucle desde 0 hasta el número de elementos ([método https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/NodeList.html#getLength() getLength()]) y obteniendo cada uno de nodos con el método item(int) de la clase NodeList.
Veamos un ejemplo:


1             NodeList nodosPedido = raiz.getElementsByTagName("pedido");
2             System.out.printf("Número de pedidos:%d",nodosPedido.getLength());
3             
4             for (int c=0;c<nodosPedido.getLength();c++){  // En este caso sólo devolverá uno ya que sólo hay un pedido
5                 Node nodoPedido = nodosPedido.item(c);
6                 
7             }


Ejercicio propuesto: Busca los nodos del árbol DOM que representen a un producto.
A partir del producto, navega manualmente hasta conseguir su código y cantidad.


  • En los dos casos (navegar y buscar) acabaremos teniendo un objeto de la clase Node.
A partir de ella podemos:
  • Seguir navegando con los métodos que ya vimos.
  • Obtener los atributos.
  • Obtener los nodos hijos, anteriores y posteriores.
  • Operaciones sobre los nodos como añadir, eliminar o modificar.
Además, como ya comentamos, podemos hacer uso del método getType() para determinar el tipo de nodo y así hacer una conversión en función del tipo:
Veamos un ejemplo:
 1             NodeList nodosCodigo = raiz.getElementsByTagName("codigo");
 2             System.out.printf("Número de codigos:%d%n",nodosCodigo.getLength());
 3             
 4             for (int c=0;c<nodosCodigo.getLength();c++){
 5                 Node nodoCodigo = nodosCodigo.item(c);
 6                 if (nodoCodigo.getNodeType()==Node.ELEMENT_NODE){   // Esto ya lo sabemos porque lo estamos buscando.
 7                     Element codigo = (Element)nodoCodigo;
 8                     System.out.println("Nombre de la etiqueta:" + codigo.getTagName());
 9                     Node nodoTextoCodigo = codigo.getFirstChild();
10                     if (nodoTextoCodigo.getNodeType()==Node.TEXT_NODE){ // Ya lo sabemos
11                         Text textoCodigo = (Text)nodoTextoCodigo;
12                         System.out.println("Texto del código:" + textoCodigo.getWholeText());
13                     }
14                 }
15                 
16             }


Ejercicio propuesto: Busca todos los productos del pedido con código 1 (puedes poner otro pedido más en el archivo XML para comprobar que funciona) y muestra sus códigos y cantidades, haciendo uso del método getChildNodes() y buscando por la etiqueta 'producto'.

Ejercicios propuestos

  • Dado el siguiente archivo XML:
<?xml version="1.0"?>
<company>
  <staff1>
    <name>john</name>
    <phone>465456433</phone>
    <email>gmail1</email>
    <area>area1</area>
    <city>city1</city>
  </staff1>
  <staff2>
    <name>mary</name>
    <phone>4655556433</phone>
    <email>gmail2</email>
    <area>area2</area>
    <city>city2</city>
  </staff2>
  <staff3>
    <name>furvi</name>
    <phone>4655433</phone>
    <email>gmail3</email>
    <area>area3</area>
    <city>city3</city>
  </staff3>
</company>
Crea las expresiones regulares necesarias para verificar que dicho archivo sólo contiene etiquetas 'staffXX' siendo XX un número, <name>texto</name>, <phone>9 números como máximo</phone> e <email>dir. correo válida</email>
Lee el archivo de disco y comprueba que pasa el filtro de la/s expresiones regulares creadas.
Paso dicho archivo a un árbol DOM y procésalo para crear una lista de objetos de una clase Staff creada por ti previamente.
Ordena dicha dicha por nombre y ciudad.
Muestra los datos ordenados de las dos formas.


Parte de la solución la podéis encontrar en este enlace.



-- Ángel D. Fernández González -- (2017).