La lógica de SAX se basa en paradigma ya utilizado en Swing: programación orientada a eventos. El analizador va recibiendo una serie de eventos (retrollamadas), al estilo de los listener de AWT y Swing, a medida que va leyendo las etiquetas. Un ejemlplo:
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
/***************************************************************************
* Manejador de eventos SAX
***************************************************************************/
public class Manejador extends DefaultHandler {
public void setDocumentLocator(Locator loc) {
}
public void startDocument() {
}
public void endDocument() {
}
public void processingInstruction(String destino, String datos) {
}
public void startPrefixMapping(String prefijo, String uri) {
}
public void endPrefixMapping(String prefijo) {
}
public void startElement(String espacioNombres, String nomLocal, String nomCompleto, Attributes atrs) {
System.out.println("Nombre local:" + nomLocal + " Nombre completo:" + nomCompleto );
for ( int i = 0; i < atrs.getLength(); i++) {
System.out.println(" ATRIB. Nombre local: " + atrs.getLocalName(i) );
System.out.println(" ATRIB. Tipo: " + atrs.getType(i) );
System.out.println(" ATRIB. Valor: " + atrs.getValue(i) );
}
}
public void endElement(String espacio, String nomLocal, String nomCompleto) {
}
public void characters(char[] ch, int inicio, int longitud) {
String cad = new String( ch, inicio, longitud);
System.out.println(" Caracteres: " + cad );
System.out.println(" Inicio:" + inicio + " Longitud:" + longitud );
}
public void ignorableWhitespace(char[] ch, int comienzo, int fin) {
}
public void skippedEntity(String nombre) {
}
public void error(SAXParseException exc) throws SAXException {
mostrarError( exc, "Se encontró un error");
}
public void fatalError(SAXParseException exc) throws SAXException {
mostrarError( exc, "Se encontró un error fatal");
}
public void mostrarError( SAXParseException exc, String aviso ) throws SAXException {
System.out.println( aviso + ". Línea: " + exc.getLineNumber() );
System.out.println( "URI: " + exc.getSystemId() );
System.out.println( "Mensaje: " + exc.getMessage() );
throw new SAXException(aviso);//
}
}
Los métodos más utilizados:
//// El lector valida de acuerdo al esquema
XMLReader xmlReader = parser.getXMLReader();
xmlReader.setFeature("http://apache.org/xml/features/validation/schema",true);
En este ejemplo desde el método main() iniciamos el análisis SAX:
import java.io.File;
import java.io.IOException;
import org.xml.sax.*;
import javax.xml.parsers.*;
/***************************************************************************
* Ejemplo de análisis XML con SAX
* Usamos DTD
***************************************************************************/
public class Inicio {
public static void main(String[] args) {
String nomArchivo = "/src/xmlSAX01/libreria3.xml";
try {
//// Directorio actual
File dirActual = new File(".");
System.out.println("El directorio actual es " + dirActual.getCanonicalPath());
//// Abro archivo XML tomando una referencia relativa al directorio actual
System.out.println("Trato de abrir el archivo " + dirActual.getCanonicalPath() + nomArchivo );
File fich = new File(dirActual.getCanonicalPath() + nomArchivo );
if ( fich.exists() )
System.out.println("Se ha abierto el archivo. Inicio del análisis" );
else {
System.out.println("No se ha abierto el archivo " + fich.getAbsolutePath());
return;
}
//// Creo y configuro una factoria
SAXParserFactory factoria = SAXParserFactory.newInstance();
factoria.setNamespaceAware(true); // Soporta espacio de nombres XML
factoria.setValidating(true); // Valida documento
//// Análisis
SAXParser parser= factoria.newSAXParser();
Manejador man = new Manejador();
parser.parse( fich, man ); // Parser del fichero 'fich' con el manejador 'man'
System.out.println("Fin del análisis.");
}
catch (IOException e) {
e.printStackTrace();
}
catch (SAXException e) {
e.printStackTrace();
}
catch (ParserConfigurationException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
El archivo DTD (libreria3.dtd), que especifica la estructura de datos, es el siguiente:
<?xml version="1.0" encoding="UTF-8" ?> <!ELEMENT libreria3 ( libro+ ) > <!ELEMENT libro (autor*, titulo, precio,rebaja?,resumen?)> <!ELEMENT autor ( #PCDATA ) > <!ELEMENT titulo ( #PCDATA ) > <!ELEMENT precio ( #PCDATA ) > <!ELEMENT rebaja ( #PCDATA ) > <!ELEMENT resumen (#PCDATA ) > <!ATTLIST resumen autor CDATA #IMPLIED fichero CDATA #REQUIRED >
El archivo XML hace referencia al DTD:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE libreria3 SYSTEM "libreria3.dtd"> <libreria3> <libro> <autor>Miguel De Cervantes</autor> <titulo>El Quijote</titulo> <precio>18</precio> </libro> <libro> <autor>Antonio Lopez</autor> <autor>Ana Perez</autor> <titulo>Cómo crecer</titulo> <precio>25</precio> <rebaja>10%</rebaja> <resumen fichero="ert34.doc" /> </libro> </libreria3>
El directorio actual es C:\DOC\Java_eclipse\docenBasico
Trato de abrir el archivo C:\DOC\Java_eclipse\docenBasico/src/xmlSAX01/libreria3.xml
Se ha abierto el archivo. Inicio del análisis
Nombre local:libreria3 Nombre completo:libreria3
Nombre local:libro Nombre completo:libro
Nombre local:autor Nombre completo:autor
Caracteres: Miguel De Cervantes
Inicio:79 Longitud:19
Nombre local:titulo Nombre completo:titulo
Caracteres: El Quijote
Inicio:117 Longitud:10
Nombre local:precio Nombre completo:precio
Caracteres: 18
Inicio:147 Longitud:2
Nombre local:libro Nombre completo:libro
Nombre local:autor Nombre completo:autor
Caracteres: Antonio Lopez
Inicio:187 Longitud:13
Nombre local:autor Nombre completo:autor
Caracteres: Ana Perez
Inicio:218 Longitud:9
Nombre local:titulo Nombre completo:titulo
Caracteres: Cómo crecer
Inicio:246 Longitud:11
Nombre local:precio Nombre completo:precio
Caracteres: 25
Inicio:277 Longitud:2
Nombre local:rebaja Nombre completo:rebaja
Caracteres: 10%
Inicio:299 Longitud:3
Nombre local:resumen Nombre completo:resumen
ATRIB. Nombre local: fichero
ATRIB. Tipo: CDATA
ATRIB. Valor: ert34.doc
Fin del análisis.