El API JAXP

Esta versi�n del programa Echo utiliza el analizador sin validaci�n. Por eso no puede decir si el documento XML contiene las etiquetas correctas, o si esas etiquetas est�n en la secuencia correcta. En otras palabras, no puede decirnos si el documento es valido. Sin embargo, si puede decirnos si es o no un documento bien-formateado.

En esta secci�n del tutorial, modificaremos el fichero slides para generar distintos tipos de errores y veremos como el analizador los maneja. Tambi�n encontraremos las condiciones de error que son ignoradas por defecto, y veremos c�mo manejarlas.

.�Introducir un Error

El analizador puede generar uno de estos tipos de errores: error fatal, error, aviso. En este ejercicio, haremos una sencilla modificaci�n en el fichero XML para introducir un error fatal. Luego veremos como es manejado en la aplicaci�n Echo.

Nota:

La estructura XML que crearemos en este ejercicio est� en slideSampleBad1.xml. La salida est� en Echo05-Bad1.log.

Una forma sencilla de introducir un error fatal es eliminar el "/" de un elemento vac�o para crear una etiqueta que no tiene su correspondiente etiqueta final. Esto constituye un error fatal, porque todos los documentos XML deben, por definici�n, estar bien formateados. Hacemos lo siguiente.

  1. Copiamos slideSample.xml a badSample.xml.

  2. Editamos badSample.xml y eliminamos el caracter mostrado abajo:
     ...
    <!-- OVERVIEW -->
    <slide type="all">
      <title>Overview</title>
      <item>Why <em>WonderWidgets</em> are great</item>
      <item/>
      <item>Who <em>buys</em> WonderWidgets</item>
    </slide>
     ...
    

    para producir.

     ...
    <item>Why <em>WonderWidgets</em> are great</item>
    <item>
    <item>Who <em>buys</em> WonderWidgets</item>   
     ...
    
  3. Ejecutamos el programa Echo sobre el nuevo fichero.

La salida que obtenemos se debe parecer a esto.

...
        ELEMENT: <item>
        CHARS:   The 
            ELEMENT: <em>
            CHARS:   Only
            END_ELM: </em>
        CHARS:    Section
        END_ELM: </item>
    CHARS:   
    END_ELM.
    CHARS:   org.xml.sax.SAXParseException: Expected "</item>" 
         to terminate element starting on line 20.
at com.sun.xml.parser.Parser.fatal(Parser.java:2800)
at com.sun.xml.parser.Parser.fatal(Parser.java:2794)
at com.sun.xml.parser.Parser.maybeElement(Parser.java:1406)
at com.sun.xml.parser.Parser.content(Parser.java:1499)
at com.sun.xml.parser.Parser.maybeElement(Parser.java:1400)
at com.sun.xml.parser.Parser.content(Parser.java:1499)
at com.sun.xml.parser.Parser.maybeElement(Parser.java:1400)
at com.sun.xml.parser.Parser.parseInternal(Parser.java:492)
at com.sun.xml.parser.Parser.parse(Parser.java:284)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:168)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:104)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:131)
at Echo05.main(Echo05.java:59)

Cuando ocurre un error fatal, el analizador no puede continuar. Por eso, si la aplicaci�n no genera una excepci�n, el manejador de errores-eventos por defecto genera una. El seguimiento de pila es generado por el manejador de la excepci�n Throwable en nuestro m�todo main.

  ...
} catch (Throwable t) {
    t.printStackTrace ();
}

.�Manejar una SAXParseException

Cuando se encontr� el error, el analizador gener� una SAXParseException -- una subclase de SAXException que identifica el fichero y la posici�n donde ocurri� el error.

Nota:

El c�digo que crearemos en este ejercicio est� en Echo06.java. La salida est� en Echo06-Bad1.log.

A�adimos el c�digo en negrita de abajo para generar un mejor mensaje de di�gnostico cuando ocurra la excepci�n.

  ...
} 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() );

} catch (Throwable t) {
    t.printStackTrace ();
}

Ahora la ejecuci�n del programa genera un mensaje de error que es un poco m�s �til, de esta forma.

** Parsing error, line 22, uri file:<path>/slideSampleBad1.xml
   Next character must be...

.�Manejar una SAXException

Un ejemplar m�s general de SAXException podr�a generarse algunas veces por el analizador, pero ocurre m�s frecuentemente cuando un error se origina en uno de los m�todos manejadores de eventos de la aplicaci�n. Por ejemplo, la firma del m�todo startDocument en el interface DocumentHandler est� definido para devolver un SAXException.

public void startDocument () throws SAXException

Todos los m�todos DocumentHandler (excepto setDocumentLocator) tienen esta declaraci�n de firma.

Una SAXException puede construirse usando un mensaje, otra excepci�n, o ambos. Por eso, por ejemplo, cuando Echo.startDocument saca un string usando el m�todo emit, cualquier excepci�n de I/O que ocurra es envuelta en un SAXException y enviada de vuelta al analizador.

private void emit (String s)
throws SAXException
{
    try {
        out.write (s);
        out.flush ();
    } catch (IOException e) {
        throw new SAXException ("I/O error", e);
    }
}
Note:

Si grabamos el objeto Locator cuando se invoc� a setDocumentLocator, podr�amos usarlo para generar una SAXParseException, que identifique el documento y la localizaci�n, en lugar de generar una SAXException.

Cuando el analizador env�a la excepci�n del vuelta al c�digo que lo invoc�, tiene sentido usar la excepci�n original para generar el seguimiento. A�adimos el c�digo en negrita de abajo para hacer esto.

 ...
} catch (SAXParseException err) {
    System.out.println ("** Parsing error" 
        + ", line " + err.getLineNumber ()
        + ", uri " + err.getSystemId ());
    System.out.println("   " + err.getMessage ());

} 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 (Throwable t) {
    t.printStackTrace ();
}

Este c�digo prueba a ver si la SAXException envuelve otra excepci�n. Si es as�, genera un seguimiento de pila originado desde donde ocurri� la excepci�n para hacer m�s sencillo apuntar al c�digo responsable del error. Si la excepci�n s�lo contiene un mensaje, el c�digo imprime el seguimiento de pila empezando por la localizaci�n donde se gener� la excepci�n.

.�Mejorar el Manejador de SAXParseException

Como la SAXParseException tambi�n puede envolver otra excepci�n, a�adimos el siguiente c�digo en negrita para usarlo en el seguimiento de pila.

  ...
} catch (SAXParseException err) {
     System.out.println ("** Parsing error" 
        + ", line " + err.getLineNumber ()
        + ", uri " + err.getSystemId ());
     System.out.println("   " + err.getMessage ());

     // Unpack the delivered exception to get the exception it contains
     Exception  x = spe;
       if (spe.getException() != null)
           x = spe.getException();
       x.printStackTrace();

} catch (SAXException e) {
    // Error generated by this application
    // (or a parser-initialization error)
    Exception	x = e;
    if (e.getException () != null)
        x = e.getException ();
    x.printStackTrace ();

} catch (Throwable t) {
    t.printStackTrace ();
}      

El programa ya est� listo para manejar cualquier excepci�n del analizador SAX que vea. Hemos visto que el analizador genera excepciones para errores fatales. Pero para los errores no fatales y los avisos nunca se generan excepciones por el manejador de error por defecto, y no se muestran mensajes. Luego, aprenderemos m�s sobre los errores y los avisos y veremos como suministrar un manejador de errores para procesarlos.

.�Manejar un ParserConfigurationException

Finalmente, recordamos que la clase SAXParserFactory puede lanzar una excepci�n si no es capaz de crear un analizador. Dicho error podr�a ocurrir si la factor�a no pudiera encontrar la clase necesaria para crear el analizador (class not found error), no se le permitiera el acceso a ella (illegal access exception), o no pudiera ejemplarizarla (instantiation error).

A�adimos el c�digo en negrita para manejar dichos errores.

} catch (SAXException e) {
    Exception	x = e;
    if (e.getException () != null)
        x = e.getException ();
    x.printStackTrace ();

} catch (ParserConfigurationException pce) {
    // Parser with specified options can't be built
    pce.printStackTrace();

} catch (Throwable t) {
    t.printStackTrace ();

Este c�digo, como el manejador SAXException, tiene en cuenta que la excepci�n reportada podr�a envolver otra excepci�n.

Nota:

Tambi�n podr�a lanzarse una javax.xml.parsers.FactoryConfigurationError si la clase especificada para la factoria por la propiedad del sistema no puede encontrarse o ejemplarizarse. Este es un error no-atrapable, ya que no se espera que el programa no pueda recuperarse.

.�Manejar una IOException

Y finalmente, dejemos de interceptar todos los objetos Throwable y capturemos las �nicas excepciones que nos quedan, las IOExceptions.

} catch (ParserConfigurationException pce) {
    // Parser with specified options can't be built
    pce.printStackTrace();

} catch (Throwable t) {
    t.printStackTrace ();
} catch (IOException ioe) {
    // I/O error
    ioe.printStackTrace();
}

.�Entender los Errores no Fatales

En general, un error no fatal ocurre cuando un documento XML falla en una restricci�n de validaci�n. Si el analizador encuentra que el documento no es valido (lo que significa que contiene una etiqueta no v�lida o en una localizaci�n no permitida), entonces se genera un evento de error. En general, los errores son generados por el ValidatingParser, dando un DTD que le dice qu� etiquetas son v�lidas.

Nota:

El fichero que crearemos en este ejercicio es slideSampleBad2.xml. La salida est� en Echo06-Bad2.log.

La especificaci�n SAX requiere que se genere un evento de error si el documento XML usa una versi�n de XML que el analizador no puede soportar. Para generar dicho error, hacemos los siguientes cambios para modificar nuestro fichero XML y especificar la version="1.2".

<?xml version='1.02' encoding='us-ascii'?>

Ahora ejecutamos nuestra versi�n del programa Echo sobre ese fichero. �Qu� sucede?

Respuesta:�No sucede nada! Por defecto, el error es ignorado. La salida el programa Echo parece la misma que si se hubiera especificado apropiadamente version="1.0". Para hacer algo m�s, necesitamos suministrar nuestro propio manejador de error. Haremos esto m�s adelante.

.�Manejar Errores no Fatales

Un tratamiento est�ndard para errores "no fatales", es tratarlos como si fueran fatales. Despu�s de todo, si ocurre un error de validaci�n en un documento que estamos procesando, probablemente no queremos continuar procesandolo. En este ejercicio haremos exactamente esto.

Nota:

El c�digo del programa que crearemos en este ejercicio est� en Echo07.java. La salida est� en Echo07-Bad2.log.

Para poder manejar el error, sobreescribimos los m�todos HandlerBase que manejan errores fatales, errores no fatales y avisos como parte del interface ErrorHandler. El analizador SAX entrega una SAXParseException a cada uno de estos m�todos, por eso generar una excepci�n cuando ocurre un error es tan simple como lanzarla de vuelta.

A�adimos el c�digo en negrita de abajo para sobreescribir los manejadores de errores.

public void processingInstruction (String target, String data)
throws SAXException
{
  nl();
  emit ("PROCESS: ");
  emit ("<?"+target+" "+data+"?>");
}

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

Ahora cuando ejecutemos nuestra aplicaci�n sobre el fichero con el n�mero de versi�n err�nea, obtendremos una excepci�n, como la mostrada aqu� (pero ligeramente reformateada para mejor lectura).

START DOCUMENT
<?xml version='1.0' encoding='UTF-8'?>
** Parsing error, line 1, uri file:/<path>/slideSampleBad2.xml
   XML version "1.0" is recognized, but not "1.2".
org.xml.sax.SAXParseException: XML version "1.0" is recognized, 
but not "1.2".
at com.sun.xml.parser.Parser.error(Parser.java:2778)
at com.sun.xml.parser.Parser.readVersion(Parser.java:1052)
at com.sun.xml.parser.Parser.maybeXmlDecl(Parser.java:984)
at com.sun.xml.parser.Parser.parseInternal(Parser.java:478)
at com.sun.xml.parser.Parser.parse(Parser.java:284)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:168)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:104)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:131)
at Echo07.main(Echo07.java:59) 
Nota:

El error realmente ocurre despu�s de que se haya generado el evento startDocument. La cabecera del documento que el programa muestra es una de las creadas en presunci�n de que todo est� bien, en vez de la que est� realmente en el fichero.

.�Manejar Avisos

Los avisos tambi�n son ignorados por defecto. Los avisos son informativos, y requieren un DTD. Por ejemplo, si un elemento est� definido dos veces en un DTD, se genera un aviso -- no es ilegal, y no causa problemas, pero es algo que queremos saber ya que podr�a no haber sido intencionado.

A�adimos el c�digo en negrita de abajo para generar un mensaje cuando ocurre un aviso.

// 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 ());
}
Nota:

Por defecto, HandlerBase lanza una excepci�n cuando ocurre un error fatal. Podr�amos sobreescribir el m�todo fatalError para que lance una excepci�n diferente, si queremos. Pero si nuestro c�digo no lo hace, la implementaci�n del referencia del analizador SAX lo har�.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO