Programación en castellano
-Tutoriales

El API JAXP


Leer Datos de un DOM

En esta sección del tutorial, construiremos un "Document Object Model" (DOM) leyéndolo desde un fichero XML existente. Luego lo escribiremos como XML para verificar que el programa está funcionando.

. Leer un Documento XML dentro de un DOM

El DOM proporciona los APIs que nos permiten crear nodos, modificarlos, borrarlos y redistribuirlos. Por eso, es relativamente fácil crear un DOM, como veremos en Crear y Manipular un DOM.

Sin embargo, la Especificación Nivel 1 DOM es silenciosa con respecto a cómo realizar la entrada y la salida. Nos dice cómo tiene que operar un DOM, pero no cubre los métodos para leer o escribir XML. Como resultado, no podemos crear un DOM desde un fichero XML existente sin salirnos de la especificación Nivel 1 de DOM.

El interface DocumentBuilder de JAXP estandariza la solución a este problema especificando una variedad de métodos analizadores que toman un objeto File o un stream de entrada, o un objeto InputSource de SAX, o una URI. Cuando invocamos a uno de estos métodos, una implementación de DocumentBuilder devuelve un objeto org.w3c.dom.Document.

Nota:

Para hacer la salida de DOM, utilizaremos una característica de la implementación de referencia. Los analizadores de diferentes fabricantes podrían usar otros mecanismos para conseguir el objetivo.

. Crear el Esqueleto

Ahora que hemos visto una rápida introducción de cómo crear un DOM, construyamos un sencillo programa que lea un documento XML en un DOM y luego lo escribamos de vuelta de nuevo.

Nota:

El código explicado en esta sección está en DomEcho01.java. Los ficheros sobre los que opera son slideSample01.xml y slideSample10.xml. La salida está en DomEcho01-01.log y DomEcho01-10.log. El fichero slideSample10.xml referencia a slideshow3.dtd que, a su vez, referencia a un (muy sencillo) xhtml.dtd.

Empezamos con una lógica básica normal para una aplicación, y chequeamos para asegurarnos que se le ha suministrado un argumento en la línea de comandos:

public class DomEcho {
    public static void main (String argv [])
    {
        if (argv.length != 1) {
            System.err.println ("Usage: java DomEcho filename");
            System.exit (1);
        }
    }// main

}// DomEcho

. Importar las Clases Necesarias

En esta sección vamos a ver todas las clases nombradas individualmente. Es decir que podremos ver de dónde viene cada clase que queremos referenciar en la documentación del API. En nuestra propia aplicación, también podríamos querer reemplazar las sentencias importantes, como las de abajo, con la forma corta: javax.xml.parsers.*.

Añadimos estas líneas para importar los APIs JAXP que vamos a usar:

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

Añadimos estas líneas para las excepciones que pueden lanzarse cuando se analiza un documento XML:

import org.xml.sax.SAXException;  
import org.xml.sax.SAXParseException;

Añadimos estas líneas para leer un fichero XML de ejemplo e identificar errores:

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

Finalmente, importamos la defición del W3C para un DOM y sus excepciones:

import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
Nota:

Las DOMExceptions sólo se lanzan cuando atraviesan o manipulan un DOM. Los errores que ocurren durante el análisis o reporte usando un mecanismo diferente que este se cubren abajo.

. Declarar el DOM

La clase org.w3c.dom.Document es el nombre W3C para un DOM. Siempre que analizemos o creemos un documento XML, resultará un Document. Queremos referenciar este objeto desde otro método más tarde en este tutorial, por eso lo definimos como un objeto global:

public class DomEcho
{    
    static Document document;

    public static void main (String argv [])
    {

Necesita ser static, porque vamos a generar su contenido desde el método main dentro de unos minutos.

. Manejar Erorres

Luego, entramos en la lógica de manejo de errores. Esta es la misma lógica que vimos en Manejar Errores en el tutorial de SAX, por eso no entraremos en detalles ahora. El único punto que merece la pena observar es que un constructor de documentos conforme el JAXP es necesario que reporte excepciones SAX cuando tiene un problema analizando un documento XML. El analizador DOM no tiene que usar realmente un analizador SAX internamente, pero como el estándard SAX estaba realmente aquí, parecía tener sentido usarlo para reportar errores. Como resultado, el código de manejo de errores para aplicaciones DOM y SAX es bastante similar.

public static void main (String argv [])
{
    if (argv.length != 1) {
        ...
    }

    try {
    } catch (SAXParseException spe) {
       // Error generated by the parser
       System.out.println ("\n** Parsing error" 
          + ", line " + spe.getLineNumber ()
          + ", uri " + spe.getSystemId ());
       System.out.println("   " + spe.getMessage() );
       // Use the contained exception, if any
       Exception  x = spe;
       if (spe.getException() != null)
           x = spe.getException();
       x.printStackTrace();
    } catch (SAXException sxe) {
       // Error generated by this application
       // (or a parser-initialization error)
       Exception  x = sxe;
       if (sxe.getException() != null)
           x = sxe.getException();
       x.printStackTrace();

    } catch (ParserConfigurationException pce) {
       // Parser with specified options can't be built
       pce.printStackTrace();
    } catch (IOException ioe) {
       // I/O error
       ioe.printStackTrace();
    }
}// main 

. Ejemplarizar la Factoría

Luego añadimos el código en negrita de abajo para obtener un ejemplar de una factoría que nos puede ofrecer un constructor de documentos:

public static void main (String argv [])
{
    if (argv.length != 1) {
        ...
    }
    DocumentBuilderFactory factory = 
		DocumentBuilderFactory.newInstance();
    try {

. Obtener un Analizador y Analizar el Fichero

Ahora, añadimos el código en negrita de abajo para obtener un ejemplar de un analizador, y lo usamos para analizar el fichero especificado:

try {
   DocumentBuilder builder = factory.newDocumentBuilder();
   document = builder.parse( new File(argv[0]) );
} catch (SAXParseException spe) {

. Escribir el XML

En este punto, el código tiene la habilidad de leer y analizar un documento XML. Para escribir el documento para su inspección, necesitamos un paso fuera del estándard del nivel 1 de DOM que crea la sección DOM del JAXP. Las operaciones de escritura de DOM no se especificaron hasta el nivel 3 de DOM. Para obtenerlas mientras tanto, forzamos el objeto Document devuelto por DocumentBuilder al objeto real que la implementación de referencia devuelve: XmlDocument.

Nota:

Este material es específico de Project X, la implementación de referencia de Sun. El material de esta sección no forma parte del estándard. En su lugar, representa funcionalidades útiles que podríamos necesitar para aprovecharnos hasta que se haya estandarizado algún mecanismo equivalente. Como no forma parte del estándard JAXP, las funcionalidades descritas aquí podrían muy bien no existir en otros analizadores estándards JAXP.

. Usar XmlDocument

Empezamos añadiendo las sentencias import que definen la clase:

import org.w3c.dom.Document;
import org.w3c.dom.DOMException;

import com.sun.xml.tree.XmlDocument;

public class DomEcho
{  

El prefijo com.sun. de esta clase es nuestra advertencia del hecho de que nos estamos moviendo fuera del estándard JAXP, y haciendo uso de una característica de la implementación de referencia de Sun.

Luego, añadimos el código en negrita de abajo para forzar el objeto Document a XmlDocument y escribirlo:

try {
  DocumentBuilder builder = factory.newDocumentBuilder();
  document = builder.parse( new File(argv[0]) ); 
           
  XmlDocument xdoc = (XmlDocument) document;
  xdoc.write (System.out);

} catch (SAXParseException spe) {

. Ejecutar el Programa

A través del tutorial DOM, usaremos el ejemplo de diapositivas creado en la sección SAX. En particular, usaremos slideSample01.xml, un sencillo fichero XML sin mucho dentro, y slideSample10.xml, un ejemplo más complejo que incluye un DTD, instrucciones de procesamiento, referencias a entidades, y una sección CDATA.

Para las instrucciones de cómo compilar y ejecutar nuestro programa, puedes ver Compilar el Programa y Ejecutar el Programa, del tutorial de SAX. Sustituimos "Echo" por "DomEcho" como el nombre del programa, y ya estamos listos. Cuando ejecutemos el programa sobre slideSample01.xml, ésta es la salida que veremos:

<?xml version="1.0" encoding="UTF-8"?>

<!--  A SAMPLE set of slides  -->
<slideshow title="Sample Slide Show" date="Date of publication" 
	author="Yours Truly">

    <!-- TITLE SLIDE -->
    
  <slide type="all">
      
    <title>Wake up to WonderWidgets!</title>
    
  </slide>

    
  <!-- OVERVIEW -->
    
  <slide type="all">
      
    <title>Overview</title>
      
    <itdestacar>Why 
      <destacar>WonderWidgets</destacar> are great
    </itdestacar>
      
    <item />
      
    <itdestacar>Who 
      <destacar>buys</destacar> WonderWidgets
    </itdestacar>
    
  </slide>


</slideshow>

Cuando ejecutamos el programa sobre slideSample10.xml, el resultado es muy similar. En particular, observamos que la referencia de entidad permanece igual que como fue escrita originalmente (no es reemplazada con el texto de la entidad):

<itdestacar>
 &copyright;
</itdestacar>

También, observa que la sección CDATA se ha preservado:

   <itdestacar>
      <![CDATA[Diagram.                         
    frobmorten <------------ fuznaten
        |            <3>        ^
        | <1>                   |   <1> = fozzle
        V                       |   <2> = framboze    
      staten--------------------+   <3> = frenzle
                     <2>
      ]]>
    </itdestacar>

. Información Adicional

Ahora que hemos leído con éxito un DOM, hay una o dos cosas más que necesitamos saber para poder usar DocumentBuilder de forma efectiva.

  • Configurar la Factoría
  • Manejar Errores de Validación

. Configurar la Factoría

Por defecto, la factoría devuelve un analizador sin validación que no sabe nada sobre espacios de nombres. Para obtener un analizador con validación, y/o uno que entienda de espacios de nombres, configuramos la factoría para seleccionar cualquiera de estas opciones usando los comandos en negrita de abajo:

public static void main (String argv [])
{
    if (argv.length != 1) {
        ...
    }
    DocumentBuilderFactory factory = 
	DocumentBuilderFactory.newInstance();
    factory.setValidating(true);
    factory.setNamespaceAware(true);
    try {
            ...
Nota:

No es necesario que los analizadores conformes con JAXP soporten todas las combinaciones de estas opciones, incluso aunque el analizador de referencia lo haga. Si especificamos una combinación de opciones inválida, la factoría generará una ParserConfigurationException cuando intentemos obtener un ejemplar del analizador.

Aprenderemos más sobre cómo usar los espacios de nombres en la última página del tutorial DOM, Usar Espacios de Nombres. Para completar esta sección, queremos aprender algo sobre...

. Manejar Errores de Validación

Recuerda que la respuesta por defecto a un error de validación, según lo dictado por el estándard, es no hacer nada. El estándard JAXP requiere que se lancen excepciones SAX, por eso usamos exactamente el mismo mecanismo de manejo de errores que usamos en la aplicación SAX. En particular, necesitamos usar el método setErrorHandler de DocumentBuilder para suminstrarle un objeto que implemente el interface ErrorHandler de SAX.

Nota:

DocumentBuilder también tiene un método setEntityResolver que podemos usar.

El código de abajo usa un adaptador de clase interna anónimo para proporcionar este ErrorHandler. El código en negrita es la parte que se asegura de que los errores de validación generen una excepción:

builder.setErrorHandler(
  new org.xml.sax.ErrorHandler() {
      // ignore fatal errors (an exception is guaranteed)
      public void fatalError(SAXParseException exception)
      throws SAXException {
      }

      // treat validation errors as fatal
      public void error (SAXParseException e)
      throws SAXParseException
      {
        throw e;
      }

      // dump warnings too
      public void warning (SAXParseException err)
      throws SAXParseException
      {
        System.out.println ("** Warning"
           + ", line " + err.getLineNumber ()
           + ", uri " + err.getSystemId ());
        System.out.println("   " + err.getMessage ());
      }
  }
); 

Este código usa una clase interna anónima para generar un ejemplar de un objeto que implementa el interface ErrorHandler. Como no tiene nombre de clase, es "anónima". Podemos pensar en ella como un ejemplar de "ErrorHandler", aunque técnicamente es un ejemplar sin nombre que implementa el interface especificado. El código es sustancialmente el mismo que el descrito en la sección Manejo de Errores del tutorial SAX.

Nota:

Las clases internas se soportan desde la versión 1.2 de la plataforma Java. Si estámos codificando para la versión 1.1, crearemos una clase externa que implemente ErrorHandler.

 
Patrocinados
 

Copyright © 1999-2007 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad
Mantenida por: Claudio y Dani.

Hospedaje web y servidores dedicados linux por Ferca Network

red internet: jugar gratis | amor | navidad 2009 | registro de dominios | servidores dedicados
más internet: comprar | gratis | posicionamiento en buscadores | decoración libre | gifs animados