Manejo de Ficheros - AC
Manejo de Ficheros - AC
Manejo de Ficheros - AC
Índice
1. Manejo de ficheros ................................................................................................................................ 1
1.1. Accesos a ficheros .......................................................................................................................... 1
1.2. Gestión de flujos de datos .............................................................................................................. 2
1.2.1. Ficheros de caracteres ............................................................................................................ 2
1.2.2. Ficheros binarios..................................................................................................................... 4
1.3. Objetos serializables ....................................................................................................................... 7
2. Trabajo con ficheros XML ....................................................................................................................... 9
2.1. Acceso a datos con DOM ................................................................................................................ 9
2.1.1. DOM y Java ........................................................................................................................... 11
2.1.2. Generar árbol DOM .............................................................................................................. 12
2.1.3. Recorrer un árbol DOM......................................................................................................... 13
2.1.4. Modificar y serializar un árbol DOM ...................................................................................... 15
2.2. SAX............................................................................................................................................... 16
2.2.1. Abrir XML con SAX desde Java .............................................................................................. 17
2.2.2. Recorrer XML con SAX .......................................................................................................... 17
2.3. Crear un documento XML con StAX .............................................................................................. 20
RAMA: Informática CICLO: Desenvolvemento de Aplicacions Multiplataforma
MÓDULO Acceso a datos CURSO: 2º
PROTOCOLO: Apuntes clases AVAL: 1 DATA: 2016/2017
UNIDAD COMPETENCIA
1. Manejo de ficheros
Una de las maneras más sencillas en Java de conseguir la persistencia es usando ficheros. Veremos a
continuación algunas alternativas que existen en Java.
1
http:/docs.oracle.com/javase/8/docs/api/java/io/File.html
Ejemplo 1
File f = new File ("d:\\textos\ejemplo.txt") ;
El resultado será:
Nombre: ejemplo.txt
Directorio padre: d:\textos\
Ruta absoluta: d:\textos\ejemplo.txt
Actividad 1
Muestra, por separado, la lista de ficheros y directorios de un directorio dado.
2
Ver en http://docs.oracle.com/javase/8/docs/api/java/io/package-summary.html todas las posibilidades
int i ;
while ((i = fich.read()) != -1) // se lee un carácter
System.out.print((char) i);
fich.close(); // cerrar fichero
} catch (FileNotFoundException e) {
System.err.println("Fichero no encontrado");
} catch (IOException e) {
System.err.println("Error de E/S");
}
}
}
El método read devuelve el carácter leído como un entero o -1 si se ha llegado al final del
fichero.
En el ejemplo anterior si quisiésemos leer de 10 en 10 caracteres podemos usar un buffer:
char b[]= new char[10];
while ((i = fich.read(b)) != -1)
System.out.println(b);
En este caso el método read devuelve el numero de caracteres leídos o -1 si se ha llegado al final
del fichero.
Una vez se han leído o se han escrito todos los datos necesario se ha de cerrar el flujo para
liberar recursos.
El flujo FileWriter permite escribir caracteres en un fichero de modo secuencial. Si es el fichero
de destino existe se vacía por lo que si se desea añadir contenido al final del mismo sin eliminar
el contenido anterior se ha de usar el constructor:
FileWriter (String ruta, boolean añadir)
Donde el parámetro ruta indica la localización del archivo en el sistema operativo y el parámetro
añadir igual a true indica que se van añadir datos al final del fichero..
Ejemplo 3
import java.io.*;
public class Ejemplo3 {
Si deseamos añadir al final del archivo deberemos pasarle un objeto de tipo FileWriter con el
parámetro append a true.
PrintWriter fich = new PrintWriter(new FileWriter(f,true));
Ejemplo 6
import java.io.*;
public class Ejemplo6 {
public static void main(String[] args) throws IOException {
File fichero = new File("d:\\FichBytes.dat");
// crea flujo de salida hacia el fichero
FileOutputStream fileout = new FileOutputStream(fichero);
// crea flujo de entrada
FileInputStream filein = new FileInputStream(fichero);
int i;
for (i = 1; i < 100; i++)
fileout.write(i); // escribe datos en el flujo de salida
fileout.close(); // cerrar flujo salida
Para añadir bytes al final del fichero usaremos el siguiente constructor para FileOutputStream, colocando
en el segundo parámetro del constructor el valor true:
FileOutputStream fileout = new FileOutputStream (fichero, true);
Al igual que con los ficheros de caracteres no es obligatorio leer elemento a elemento sino que
podremos trabajar con un buffer.
Ejemplo 7: Descargar un fichero
FileOutputStream fout=new FileOutputStream("salida.mp3");
InputStream is= new URL("http://example.com/cancion.mp3").openStream();
int i;
byte[] buffer = new byte[1000];
while ((i = is.read(buffer)) != -1) {
fout.write(buffer, 0, i);
}
fout.close();
is.close();
Para leer y escribir datos de tipos primitivos: int, float, long, etc. usaremos las clases DatalnputStream y
DataOutputStream. Estas clases además de los métodos read() y write() vistos anteriormente
proporcionan métodos para la lectura y escritura de tipos. Algunos de los métodos se muestran en la
siguiente tabla:
MÉTODOS PARA LECTURA MÉTODOS PARA ESCRITURA
boolean readBoolean(); void writeBoolean(boolean v);
byte readByte(); void writeByte(int v);
short readShort(); void writeBytes(String s);
char readChar(); void writeChars(String s);
int readInt(); void writeChar(int v);
long readLong(); void writeInt(int v);
float readFloat(); void writeFloat(float v);
double readDouble(); void writeDouble(double v);
String readUTF(); void writeUTF(String str);
El siguiente ejemplo inserta datos en el fichero FichData.dat, los datos los toma de dos arrays, uno
contiene los nombres de una serie de personas y el otro sus edades, recorremos los arrays y vamos
escribiendo su contenido en el fichero:
Ejemplo 7
import java.io.*;
El siguiente ejemplo visualiza los datos grabados anteriormente en el fichero, se deben recuperar el
mismo orden en el que se insertaron, es decir, primero obtenemos el nombre y luego la edad:
Ejemplo 8
import java.io.*;
public class Ejemplo8 {
public static void main(String[] args) throws IOException {
File fichero = new File("D:\\FichData.dat");
FileInputStream filein = new FileInputStream(fichero);
DataInputStream datain = new DataInputStream(filein);
String n;
int e;
try {
while (true) {
n = datain.readUTF(); // recupera el nombre
e = datain.readInt(); // recupera la edad
System.out.println("Nombre: " + n + ", edad: " + e);
}
} catch (EOFException eo) { }
datain.close(); // cerrar flujo
}
}
public Persona() { }
public Persona(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
El siguiente ejemplo escribe objetos Persona en un fichero. Necesitamos crear un flujo de salida a disco
con FileOutputStream y a continuación se vincula este con el flujo de salida ObjectOutputStream, que es
el que procesa los datos:
File fichero = new File ("D:\\FichPersona.dat");
FileOutputStream fileout = new FileOutputStream (fichero) ;
ObjectOutputStream dataOS = new ObjectOutputStream (fileout) ;
El método writeObject() escribe los objetos al flujo de salida y los guarda en un fichero en disco:
dataOS.writeObject(persona) ;
El código es el siguiente:
Ejemplo 9: Continuación
import java.io.*;
public class EscribePersona {
public static void main(String[] arg) {
Persona persona;
File fichero = new File("D:\\FichPersona.dat");
try {
FileOutputStream fileout = new FileOutputStream(fichero);
ObjectOutputStream dataOS = new ObjectOutputStream(fileout);
String nombres[] = { "Ana", "Luis Miguel", "Alicia", "Pedro" };
int edades[] = { 14, 15, 13, 15 };
Para leer objetos Persona del fichero necesitamos el flujo de entrada a disco FilelnputStream y a
continuación crear el flujo de entrada ObjectlnputStream que es el que procesa los datos y se ha de
vincular al fichero de FilelnputStream:
File fichero = new File ("d:/FichPersona.dat");
FileInputStream filein = new FileInputStream (fichero);
ObjectInputStream datain = new ObjectInputStream (filein);
El método readObject() lee los objetos del flujo de entrada, puede lanzar la excepción
ClassNotFoundException:
persona = (Persona) datain.readObject();
El código es el siguiente:
Ejemplo 9: Continuación
import java.io.*;
public class LeePersona {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Persona persona;
File fichero = new File("D:/FichPersona.dat");
if (fichero.exists()) {
FileInputStream fileIn = new FileInputStream(fichero);
ObjectInputStream dataIn = new ObjectInputStream(fileIn);
try {
while (true) { // lectura del fichero
persona = (Persona) dataIn.readObject(); // leer una Persona
System.out.println("Nombre: " + persona.getNombre()
+ ", edad: " + persona.getEdad());
}
} catch (EOFException e) {
dataIn.close();
}
} else System.out.println("El fichero no existe");
}
}
3
https://es.wikipedia.org/wiki/Document_Object_Model
El árbol DOM asociado al documento XML es el siguiente, teniendo en cuenta que faltan por expandir los
nodos pertenecientes a dos películas.
La generación del árbol DOM a partir de un documento XML se hace de la siguiente forma:
1. DOM no valida el documento mediante el esquema asociado (aunque se puede cambiar este
comportamiento) y solo comprueba que el documento este bien formado
2. El primer paso es crear el nodo raíz película asociado con el elemento <Películas>.
3. De <Películas> cuelgan en el documento tres hijos <Película> de tipo elemento, por tanto el
árbol crea 3 nodos Película descendiente de Películas.
4. Cada elemento <Película> en el documento tiene asociado un atributo fechaExtreno. En DOM,
los atributos son listas con el nombre del atributo y el valor. La lista contiene tantas tuplas
(nombre, valor) como atributos haya en el elemento. En este caso solo hay un atributo en el
elemento <Película>.
5. Cada <Película> tiene dos elementos que descienden de él y que son <Titulo> y <Director>. Al ser
elementos, estos son representados en DOM como nodos descendientes de Película, al igual que
se ha hecho con Película al descender de Películas.
6. Cada elemento <Titulo> y <Director> tiene un valor que es de tipo cadena de texto. Los valores
de los elementos son representados en DOM como nodos #text. Sin duda esta es la parte más
importante del modelo DOM. Los valores de los elementos son nodos también, a los que
internamente DOM llama #text y que descienden del nodo que representa el elemento que
contiene ese valor.
7. Hay que tener en cuenta que cuando se edita un documento XML, al ser este de tipo texto, es
posible que, por legibilidad, se coloque cada uno de los elementos en líneas diferentes o incluso
que se utilicen espacios en blanco para separar los elementos y ganar en claridad.
DOM no distingue cuándo un espacio en blanco o un salto de línea (\n) se hace porque es un
texto asociado a un elemento XML o es algo que se hace por "estética". Por eso, DOM trata todo
lo que es texto de la misma manera, creando un nodo de tipo #text y poniéndole el valor dentro
de ese nodo. En diagrama anterior el nodo #text que desciende de Película y que tiene como
valor "\n" (salto de línea) es creado por DOM ya que, por estética, se ha hecho un salto de línea
dentro del documento XML, para diferenciar claramente que la etiqueta <Titulo> es
descendiente de <Pelicula>. Sin duda, en el documento XML hay muchos más "saltos de línea"
que se han empleado para dar claridad al documento, sin embargo, en el árbol no se han
incluido ya que tantos nodos con "saltos de línea" dejarían el esquema ilegible.
8. Por último, un documento XML tiene muchas más "cosas" que las mostradas en el ejemplo:
comentarios, encabezados, espacios en blanco, entidades, etc., son algunas de ellas. Cuando se
trabaja con DOM, rara vez esos elementos son necesarios para el programador, por lo que la
librería DOM ofrece funciones que omiten estos elementos antes de crear el árbol, agilizando así
el acceso y modificación del árbol DOM.
2.1.1. DOM y Java
DOM ofrece una manera de acceder a documentos XML tanto para ser leído como para ser modificado.
Su único inconveniente es que el árbol DOM se crea todo en memoria principal, por lo que si el
documento XML es muy grande, la creación y manipulación de DOM sería intratable.
Muchas han sido las propuestas para trabajar desde Java con la gran APLICACIÓN
cantidad de parsers DOM que existen. Sin embargo, para resumir,
actualmente la propuesta principal se reduce al uso de JAXP (Java API for JAXP
XML Processing). A través de JAXP los diversos parsers garantizan la
interoperabilidad de Java. Una aplicación que desea manipular documentos PARSER DE OTROS
XML accede a la interfaz JAXP y a través de esta puede utilizar de manera REFERENCIA PARSERS
transparente los diferentes parsers que hay para manejar XML. Estos
parsers son para DOM (XT, Xalan, Xerces, …) pero también pueden ser parsers para SAX.
En los ejemplos mostrados en las siguientes secciones se utilizará la librería Xerces para procesar
representaciones en memoria de un documento XML considerando un árbol DOM. Entre los paquetes
concretos que se usarán destacan:
javax.xml.parsers.*4, en concreto javax.xml.parsers.DocumentBuilder y javax.xml.parsers.
DocumentBuilderFactory, para el acceso desde JAXP.
org.w3c.dom.*5 que representa el modelo DOM según la W3C (objetos Node, NodeList,
Document, etc. y los métodos para manejarlos).
La Figura siguiente muestra un esquema que relaciona JAXP con el acceso a DOM. Desde la interfaz JAXP
se crea un DocumentBuilderFactory. A partir de esa factoría se crea un DocumentBuilder que permitirá
cargar en él la estructura del árbol DOM (Árbol de Nodos) desde un fichero XML (Entrada XML).
Interfax JAXP
DocumentBuilderFactory factory=
DocumentBuilderFactory.newInstance()
Crear
4
Más información en http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/package-summary.html
5
Más información en http://docs.oracle.com/javase/8/docs/api/org/w3c/dom/package-summary.html
La clase DocumentBuilderFactory tiene métodos importantes para indicar qué interesa y qué no interesa
del fichero XML para ser incluido en el árbol DOM, o si se desea validar el XML con respecto a un
esquema. Algunos de estos métodos son los siguientes:
setIgnoringComments: sirve para ignorar los comentarios que tenga el fichero XML.
setIgnoringElementContentWhitespace: es útil para eliminar los espacios en blanco que no
tienen significado (Solo si esta activada la validación del documento XML).
setValidating: que valida el documento XML según el esquema definido.
Con respecto a los métodos que sirven para manipular el árbol DOM, que se encuentran en el paquete
org.w3c.dom, destacan los siguientes métodos asociados a la clase Node6:
Todos los nodos contienen los métodos getFirstChild() y getNextSibling() que permiten obtener
uno a uno los nodos descendientes de un nodo y sus hermanos.
El método getNodeType()7 devuelve una constante para poder distinguir entre los diferentes
tipos de nodos: nodo de tipo Elemento (ELEMENT_NODE), nodo de tipo #text (TEXT_NODE), etc.
Este método y las constantes asociadas son especialmente importantes a la hora de recorrer el
árbol ya que permiten ignorar aquellos tipos de nodos que no interesan (por ejemplo, los #text
que tengan saltos de línea).
El método getAttributes() devuelve un objeto NamedNodeMap (una lista con sus atributos) si el
nodo es del tipo Elemento.
Los métodos getNodeName() y getNodeValue() devuelven el nombre y el valor de un nodo de
forma que se pueda hacer una búsqueda selectiva de un nodo concreto. El error típico es creer
que el método getNodeValue() aplicado a un nodo de tipo Elemento (por ejemplo, <Titulo>)
devuelve el texto que contiene. En realidad, es el nodo de tipo #text (descendiente de un nodo
tipo Elemento) el que tiene el texto que representa el título de la película y es sobre él sobre el
que hay que aplicar el método getNodeValue() para obtener el título.
2.1.2. Generar árbol DOM
Para abrir un documento XML desde Java y crear un árbol DOM con él se utilizan las clases
DocumentBuilderFactory y DocumentBuilder, que pertenecen al paquete javax.xml.parsers, y Document,
que representa un documento en DOM y pertenece al paquete org.w3c.dom. Aunque existen otras
posibilidades, en el ejemplo mostrado seguidamente se usa un objeto de la clase File para indicar la
localización del archivo XML.
Ejemplo 10
import java.io.File;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class DOM {
public Document doc=null; // Objeto Document que almacena el DOM del XML seleccionado.
public void getDom(File f) {
try {
// Se crea un objeto DocumentBuiderFactory.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
System.out.println(factory.getClass()); // informacion sobre la clase usada
6
Más información sobre la interfaz Node en: http://docs.oracle.com/javase/8/docs/api/org/w3c/dom/Node.html
7
Para ver los valores de las contantes en: http://docs.oracle.com/javase/8/docs/api/constant-values.html#org.w3c
// Indica que el modelo DOM no debe contemplar los comentarios que tenga el XML
factory.setIgnoringComments(true);
// Ignora los espacios en blanco. Si no se hace esto entonces los
// espacios en blanco aparecen como nodos.
factory.setIgnoringElementContentWhitespace(true);
// Se crea un objeto DocumentBuilder para cargar en él la estructura
// de árbol DOM a partir del XML seleccionado.
DocumentBuilder builder = factory.newDocumentBuilder();
// Interpreta (parsea) el documento XML (file) y genera el DOM equivalente.
this.doc=builder.parse(f);
//doc=builder.parse("http://www.w3schools.com/xml/simple.xml");
El método parse() de DocumentBuilder recibe como entrada un File con la ruta del fichero XML que se
desea abrir y devuelve un objeto de tipo Document. Este objeto (doc en el ejemplo) es el árbol DOM
cargado en memoria y listo para ser tratado.
2.1.3. Recorrer un árbol DOM
Para recorrer un árbol DOM se utilizan las clases Node y NodeList que pertenecen al paquete
org.w3c.dom.
El siguiente código recorre el árbol DOM mostrando el director y el título de cada película junto con los
posibles atributos que tenga.
Ejemplo 10: Continuación
public String muestraDOM(Document doc) {
String salida = "";
Node nodo, ntemp = null;
// Obtiene el primero nodo del DOM
Node raiz = doc.getFirstChild();
// Element raiz = doc.getDocumentElement();
// Obtiene una lista de nodos con todos los nodos hijo.
NodeList nodelist = raiz.getChildNodes();
for (int i = 0; i < nodelist.getLength(); i++) { // Proceso los nodos hijo
nodo = nodelist.item(i);
// Al ejecutar este código, se observa como los nodos que encuentra son de tipo 1
// (ELEMENT_NODE) y tipo 3 (TEXT_NODE).
// Es un nodo película que hay que procesar si es de tipo Elemento
if (nodo.getNodeType() == Node.ELEMENT_NODE) {
salida += "----------------------------------\n";
NodeList nodosHijos = nodo.getChildNodes();
for (int j = 0; j < nodosHijos.getLength(); j++) {
ntemp = nodosHijos.item(j);
// Se debe comprobar el tipo de nodo que se quiere tratar por que es posible
// que haya nodos tipo TEXT que contengan retornos de carro al cambiar de
// línea en el XML.
if (ntemp.getNodeType() == Node.ELEMENT_NODE) {
// IMPORTANTE: para obtener el texto con el título accede al
// nodo TEXT hijo de ntemp y saca su valor.
salida += ntemp.getNodeName() + ": "
+ ntemp.getChildNodes().item(0).getNodeValue() + "\n";
}
}
Es una práctica común al trabajar con DOM comprobar el tipo del nodo que se está tratando en cada
momento ya que, como se ha comentado antes, un DOM tiene muchos tipos de nodos que no siempre
tienen información que merezca la pena explorar. En el código, solo se presta atención a los nodos de
tipo Elemento (ELEMENT_NODE) y de tipo #Text (TEXT_NODE).
Si queremos obtener todos los nodos de un tipo determinado de elemento (por ejemplo película)
podemos usar el método getElementsByTagName el cual devuelve una lista de nodos de ese elemento.
NodeList nodelist = doc.getElementsByTagName("Película");
En el ejemplo se ha recorrido el árbol DOM creado del documento XML. El resultado de procesar dicho
documento origina la siguiente salida:
----------------------------------
Titulo: Dune
Director: David Lynch
Atributo: fechaEstreno -> 1984
----------------------------------
Titulo: Blade Runner
Director: Ridley Scott
Atributo: fechaEstreno -> 1982
----------------------------------
Titulo: Alien: el octavo pasajero
Director: Ridley Scott
Atributo: fechaEstreno -> 1979
// Se añade el nodo de texto con el título como hijo del elemento Titulo
nodoTitulo.appendChild(textNodoTitulo);
// Se añade a película un nodo tipo texto con un retorno de carro (\n) para que
// al abrirlo con un editor de texto cada nodo salga en un línea diferente.
nodoPelicula.appendChild(doc.createTextNode("\n"));
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
Una vez se ha modificado en memoria un árbol DOM, éste puede ser llevado a fichero para lograr la
persistencia de los datos. Esto se puede hacer de muchas maneras. Una alternativa concreta se recoge
en el siguiente código.
Ejemplo 10: Continuación
public void grabaDOM(Document document, FileOutputStream ficheroSalida) throws
ClassNotFoundException, InstantiationException, IllegalAccessException {
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS ls=(DOMImplementationLS) registry.getDOMImplementation("XML 3.0 LS 3.0");
// Creamos un destino vacio
LSOutput output = ls.createLSOutput();
output.setEncoding("UTF-8");
// Establecemos el fujo de salida
output.setByteStream(ficheroSalida);
//output.setByteStream(System.out);
// Permite estribir un documento DOM en XML
LSSerializer serializer = ls.createLSSerializer();
//Establecemos propiedades del serializador
serializer.setNewLine("\r\n");;
serializer.getDomConfig().setParameter("format-pretty-print", true);
// Escribimos el documento ya sea en un fichero o en una cadena
serializer.write(document, output);
// String xmlCad=serializer.writeToString(document);
}
2.2. SAX
SAX (Simple API for XML) es otra tecnología para poder acceder a XML desde lenguajes de programación.
Aunque SAX tiene el mismo objetivo que DOM esta aborda el problema desde una óptica diferente.
Las principales características de SAX son:
SAX abre y recorre secuencialmente el fichero XML. Terminado el proceso cuando llega al final
del mismo. En SAX el programador no tiene una visión global del documento y no puede
moverse por el mismo a su antojo.
SAX, a diferencia de DOM, no carga el documento en memoria, sino que lo lee directamente
desde el fichero. Esto provoca que use muy poca memoria lo que lo hace especialmente útil
cuando los ficheros XML son muy grandes.
La lectura de un documento XML produce eventos que ocasiona la llamada a métodos.
Que se haya detectado una etiqueta de comienzo de un elemento, por ejemplo <película>.
Que se haya detectado una etiqueta de final de un elemento, por ejemplo </película>.
Que se haya detectado un atributo.
Que se haya detectado una cadena de caracteres que puede ser un texto.
Que se haya detectado un error (en el documento, de I/O, etc.).
Cuando SAX devuelve que ha detectado un evento, entonces este evento puede ser manejado
con la clase DefaultHandler8 (callbacks). Esta clase debe ser extendida y los métodos de esta
clase deben ser redefinidos (sobreescritos) por el programador para conseguir el efecto deseado
cuando SAX detecta los eventos.
Cuando SAX detecta un evento de error o un final de documento entonces se termina el
recorrido.
2.2.1. Abrir XML con SAX desde Java
Para abrir un documento XML desde Java con SAX y utilizando JAXP se utilizan las clases:
SAXParserFactory y SAXParser que pertenecen al paquete javax.xml.parsers.
Ejemplo 11
public void manejador(File ficheroXML) throws
ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
Como se puede entender siguiendo los comentarios del código, primeramente se crean los objetos
factory y parser. Además SAX, a diferencia con DOM, debe crear una instancia de una clase que extienda
a DefaultHandler (en el ejemplo ManejadorSAX) que redefine los métodos que personalizan el
comportamiento del parser cuando se produce un evento
El método parse lanza SAX para el fichero XML seleccionado y con el manejador deseado (se podrían
implementar tantas extensiones de DefaultHandler como manejadores diferentes se quisieran usar).
2.2.2. Recorrer XML con SAX
Para poder lanzar el parser antes es necesario haber definido la clase que extiende DefaultHandler.
Esta clase extiende, entre otros, los métodos startDocument, endDocument, startElement, endElement y
characters. Estos métodos (callbacks) se invocan cuando, durante el recorrido del documento XML, se
detecta un evento de comienzo del documento, fin del documento, comienzo de elemento, final de
elemento o cadena de caracteres.
8
Ver más en http://docs.oracle.com/javase/8/docs/api/org/xml/sax/helpers/DefaultHandler.html
En el ejemplo que veremos a continuación, cada método tiene las siguientes funciones:
startDocument: cuando se detecta con SAX un evento de comienzo de un documento, entonces
SAX invoca a este método. En el ejemplo muestra solamente un mensaje informativo.
endDocument: SAX invoca este método cuando detecta el final del documento.
startElement: cuando se detecta con SAX un evento de comienzo de un elemento, entonces SAX
invoca a este método. En el ejemplo lo que hace es comprobar de qué tipo de elemento se trata:
Si es <Pelicula> entonces saca el valor de su atributo 9 y lo concatena con una cadena
(cadena_resultado) que tendrá toda la salida después de recorrer todo el documento.
Si es <Titulo> muestra el título del película.
Si es <Director> muestra el director del película.
Si es otro tipo de elemento no hará nada.
endElement(): cuando se detecta con SAX un evento de final de un elemento, entonces SAX
invoca a este método. El en ejemplo el método comprueba si es el final de un elemento
<Pelicula>. Si es así, entonces muestra una línea para separar las películas.
characters(): cuando se detecta con SAX un evento de detección de cadena de texto, entonces
SAX invoca a este método. El método lo que hace en el ejemplo es limpiar la cadena leída y si
tiene contenido mostrarlo..
Un ejemplo de clase ManejadorSAX es el siguiente:
Ejemplo 11: Continuación
class ManejadorSAX extends DefaultHandler {
@Override
public void startDocument() {
System.out.println("Comienzo del Documento XML");
}
@Override
public void endDocument() {
System.out.println("Final del Documento XML");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts)
throws SAXException {
if (qName.equals("Pelicula")) {
for (int i=0;i<atts.getLength();i++)
System.out.println(atts.getLocalName(i)+":\t"+atts.getValue(i));
}
else if (qName.equals("Titulo")) System.out.print("El título es: ");
else if (qName.equals("Director")) System.out.print( "El director es: ");
}
@Override
public void endElement(String uri, String localName, String qName) throws
SAXException {
if (qName.equals("Director")) System.out.println("-------------------------");
}
9
Ver métodos disponibles en http://www.saxproject.org/apidoc/org/xml/sax/Attributes.html
@Override
public void characters(char[] ch, int inicio, int longitud) throws SAXException {
String car=new String(ch, inicio, longitud);
car = car.replaceAll("[\t\n]",""); //quitar saltos de línea y tabuladores
if (car.trim().length()>0) System.out.println ("\t" + car);
}
@Override
public void error(SAXParseException e) {
System.out.println("Error: "+e.getMessage());
}
@Override
public void fatalError(SAXParseException e) {
System.out.println("Error fatal: "+e.getMessage());
}
}
Si se aplica el código anterior al contenido del documento XML, el resultado sería el siguiente:
Comienzo del Documento XML
fechaEstreno: 1984
El título es: Dune
El director es: David Lynch
-------------------------
fechaEstreno: 1982
El título es: Blade Runner
El director es: Ridley Scott
-------------------------
fechaEstreno: 1979
El título es: Alien: el octavo pasajero
El director es: Ridley Scott
-------------------------
Final del Documento XML
writer.writeStartDocument();
writer.writeStartElement("peliculas");
writer.writeStartElement("pelicula");
writer.writeAttribute("fechaEstreno", "1979");
writer.writeAttribute("duracion", "132");
writer.writeStartElement("Titulo");
writer.writeCharacters("Star Trek");
writer.writeEndElement();
writer.writeStartElement("Director");
writer.writeCharacters("Robert Wise");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
writer.close();
}