dbf.setValidation(true)

Download Report

Transcript dbf.setValidation(true)

Document Object Model
Curso: XML, de los datos a la presentación
Julio de 2005
CAPTIVA · www.captiva.es
¿Qué es DOM?

DOM (Document Object Model)

Serie de recomendaciones W3C

API que define objetos presentes en documentos XML

Inicialmente (DOM nivel 0)


La forma que implementaron navegadores de manipular las
páginas  Javascript
Actualmente DOM nivel 3. Sólo algunas son ya
recomendaciones

DOM Level 3 Core, DOM Level 3 Validation
DOM como estructura

Un Document DOM es un árbol de nodos


Jerarquía contiene nodos que representan nodos XML (raíz,
elemento, comentario, …)
SAX era una API muy simple

El programador debe implementar toda la lógica

No hay estado

No se puede modificar fichero

DOM abstrae al programador de la representación del árbol

Simplemente se carga el fichero y se obtiene un objeto Document
con toda la estructura en memoria representada en base a objetos

Permite editar, copiar, eliminar nodos/ramas del árbol
Evolución de la API

DOM Level 1

Soporte XML 1.0 y HTML

Cada elemento HTML representado mediante una interfaz

DOM Level 2

Incluye soporte para namespaces

También incorpora soporte para CSS, y eventos

DOM Level 3

Mejor soporte para crear objeto Document

Mejor soporte namespaces

Soporte para XPath
Soporte para el futuro

A través de la interfaz DOMImplementation
de la API podemos determinar si la
implementación que estamos usando soporta
una característica
...
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder docb = dbf.newDocumentBuilder();
DOMImplementation domImpl = docb.getDOMImplementation();
if (domImpl.hasFeature("StyleSheets", "2.0")) {
System.out.println(“Version 2.0 de hojas de estilo soportadas.");
} else {
System.out.println(“Hojas de estilo no soportadas.");
}
...
Repaso a tipos de nodos XML
Repaso a tipos de nodos XML
(II)

Nodo DOM


Documento  Padre de todos (nodo raíz)
Nodos básicos



Elemento, atributo, texto
Un nodo atributo contiene info sobre elemento pero no se
considera realmente hijo del elemento (como en XPath)
Otros nodos




CDATA (puede contener etiquetas que no se procesan)
Comentarios (habitualmente ignorados por la aplicación)
PI
Fragmentos de documento



Un documento debe tener elemento raíz
Un fragmento no tiene por qué
Entidades, notations, …
Procesado documento XML

Cargar e interpretar un documento XML en
memoria con DOM sólo se requieren tres
pasos:




Crear una factoría DocumentBuilderFactory
A partir de ésta obtener un DocumentBuilder
El objeto DocumentBuilder es el que lee el
fichero XML y crea el objeto Document
De forma similar a los ejemplos creados para
SAX, vamos a crear una aplicación basada en
DOM que imprima información sobre
documentos XML.
Leyendo documentos

Creamos un nuevo proyecto y añadimos una clase EjemploDOM:
import
import
import
import
javax.xml.parsers.DocumentBuilder;
javax.xml.parsers.DocumentBuilderFactory;
java.io.File;
org.w3c.dom.Document;
public class EjemploDOM {
public static void main(String args[]) {
for (int i = 0; i < args.length; i++) {
System.out.println("Procesando fichero " + args[i] + "...");
File file = new File(args[i]);
Document doc = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(file);
} catch (Exception e) {
System.out.print("Error procesando fichero: "+e.getMessage());
}
}
}
}
Leyendo documentos (II)



Esta clase simplemente carga en memoria uno
a uno los ficheros XML que se especifiquen en
la línea de comandos
JAXP dispone de un parser DOM por defecto
Podemos igualmente escoger otro con:
java -Djavax.xml.parsers.DocumentBuilderFactory= \
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
-jar Programa.jar
Opciones de la factoría

Existen multitud de opciones que le podemos habilitar al parser a
través de funciones que aceptan valores true/false. Algunas son:

setCoalescing(): Si se fija junta secciones CDATA con texto
que lo. Falso por defecto

setExpandEntityReferences(): Determina si se expanden
ENTITIES externas. True por defecto

setIgnoringComments(): Si se habilita se ignoran
comentarios. False por defecto

setIgnoringElementContentWhitespace(): Si se habilita se
eliminan espacios extras (como en HTML). Falso por defecto.

setNamespaceAware(): Si se habilita se presta atención a los
namespaces. Falso por defecto

setValidating(): Se valida el documento contra DTD/Schema
(si lo soporta el parser) especificado. Falso por defecto.
Habilitamos validación

Vamos a habilitar validación en nuestro ejemplo. Si el
parser no la implementa saltará una excepción.
…
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
dbf.setValidation(true);
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(file);
...
Habilitamos validación

Vamos a habilitar validación en nuestro ejemplo. Si el
parser no la implementa saltará una excepción.
…
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
dbf.setValidation(true);
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(file);
...
Obteniendo el elemento raíz

Para obtener el elemento raíz de un documento
utilizamos el método getDocumentElement().

El objeto devuelto es org.w3c.dom.Element.
...
//Paso 1: Obtener elemento raíz
doc = db.parse(file);
Element root = doc.getDocumentElement();
System.out.println("Elemento raíz: " +
root.getNodeName());
...
Obteniendo los nodos hijos

Partiendo del elemento raíz, podemos recuperar todos sus nodos
hijos mediante el método del objeto Element
getChildNodes().
...
//Paso 1: Obtener elemento raíz
doc = db.parse(file);
Element root =
doc.getDocumentElement();
System.out.println("Elemento raíz: " +
root.getNodeName());
//Paso 2: Nodos hijo del elemento raíz
NodeList children = root.getChildNodes();
System.out.println("Hay "+children.getLength()
+" nodos en el documento.");
...
Recorriendo el árbol

Todos los nodos disponen de métodos getFirstChild() y getNextSibling() que nos
permiten recorrer el árbol. Vamos a crear una función recursiva que vaya recorriendo todo el
árbol e imprimiendo los nombres y valores de los nodos.
...
//Paso 3: Recorrido del árbol
stepThrough(root,0);
...
static void stepThrough(Node node,int level){
StringBuffer sb = new StringBuffer();
//Tantos caracteres por delante como nivel
for(int i=0; i<level;i++)
sb.append("-");
System.out.println(sb.toString() +
node.getNodeName()+ "=“ +
escapeString(node.getNodeValue()));
for (Node child = node.getFirstChild();
child != null; child = child.getNextSibling()) {
stepThrough(child, level+1);
}
}
Atributos

Los atributos no son visualizados porque no se consideran hijos de los elementos. Éstos han de recuperarse
mediante getAttributes()
static void stepThrough(Node node,int level){
StringBuffer sb = new StringBuffer();
//Tantos caracteres por delante como nivel
for(int i=0; i<level;i++)
sb.append("-");
System.out.println(sb.toString() +
node.getNodeName()+ "=“ +
escapeString(node.getNodeValue()));
if(node.getAttributes()!=null){
if(node.getAttributes()!=null){
NamedNodeMap atts = node.getAttributes();
for(int i=0;i< atts.getLength();i++ ){
System.out.println(sb.toString() +" Atributo: " +
atts.item(i).getNodeName()+"="+

escapeString(atts.item(i).getNodeValue()));
}
}
for (Node child = node.getFirstChild();
child != null; child = child.getNextSibling()) {
stepThrough(child, level+1);
}
}
Ejemplo2: Manipulación de
árboles




Vamos a crear otro ejemplo que demuestre que DOM no sólo permite
recorre un árbol, sino también modificarlo y visualizarlo
Creamos un nuevo proyecto para EjemploDOM2
Partimos del ejemplo anterior
El programa se alimentará con un fichero suma-entrada.xml
<?xml version="1.0" encoding="utf-8"?>
<suma>
<sumando>1.4</sumando>
<sumando>21.4</sumando>
<sumando>31.24</sumando>
<sumando>0.4</sumando>
<sumando>2.15</sumando>
<sumando>7</sumando>
</suma>

El programa deberá procesar los elementos <sumando> y generar un
elemento que insertará al final <resultado> con el resultado de la suma
Esqueleto

Ahora sólo vamos a procesar un único fichero de entrada
import
import
import
import
javax.xml.parsers.DocumentBuilder;
javax.xml.parsers.DocumentBuilderFactory;
java.io.File;
org.w3c.dom.*;
public class EjemploDOM2 {
public static void main(String args[]) {
if(args.length == 0){
System.err.println("No se ha especificado ningún fichero de
entrada");
System.exit(1);
}
File file = new File(args[0]);
}
}
Lectura del fichero

Igual que antes hay que leer el fichero
Document doc = null;
try {
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dbf.setValidating(true);
doc = db.parse(file);
//Paso 1: Obtener elemento raíz
Element root = doc.getDocumentElement();
} catch (Exception e) {
System.out.print("Error procesando fichero:
"+e.getMessage());
e.printStackTrace();
}
Procesado del documento

El segundo paso va a ser leer el que realice los
cálculos. Llamaremos a una función
computeAdition:
…
//Paso 1: Obtener elemento raíz
Element root = doc.getDocumentElement();
//Paso 2: Realizamos los cálculos
double suma = computeAdition(root);
…
Procesado del documento (II)

Función computeAdition:
static double computeAdition(Element root) throws Exception {
double suma = 0;
if(!root.getNodeName().equals("suma")){
throw new Exception("El elemento raíz debe ser <suma>");
}
if(root.hasChildNodes()){
NodeList children = root.getChildNodes();
for(int i=0; i<children.getLength();i++){
if(children.item(i).getNodeType()!=Node.ELEMENT_NODE)
continue;
if(!children.item(i).getNodeName().equals("sumando")){
throw new Exception("Elemento no soportado (debe ser <sumando>): " + children.item(i).getNodeName());
}
Node sumando = children.item(i).getFirstChild();
if(sumando == null || sumando.getNodeType() != sumando.TEXT_NODE)
throw new Exception("Sumando con contenido incorrecto");
try{
suma += Double.parseDouble(sumando.getNodeValue());
}catch(NumberFormatException e){
throw new Exception("Valor de sumando inválido");
}
}
}
return suma;
}
Modificación del árbol


Para modificar el árbol hemos de crear primeramente los nodos a través de las
fuciones de Document createNode() o createXXXNode()
Después se insertan los nodos mediante funciones appendChild() ó
insertBefore()
...
//Paso 2: Realizamos los cálculos
double suma = computeAdition(root);
//Paso 3: Insertamos nuevos nodos
insertResult(doc, root, suma);
...
static void insertResult(Document doc, Element root, double result){
Node texto = doc.createTextNode("" + result);
Node elemento = doc.createElement("resultado");
elemento.appendChild(texto);
root.appendChild(elemento);
}
Imprimir árbol

Para imprimir la salida del árbol a un
documento XML hay varias alternativas

La más sencilla  Ir imprimendo el código
XML en base a la información del árbol
if(node.getNodeType()==Node.ELEMENT_NODE)
System.out.println(“<“+node.getNodeName()+”>);

Utilizar una transformación de identidad.
Se trata de una transformación XSLT (API
javax.xml.transform) sin aplicar ninguna
plantilla.
Imprimir árbol (II)

Ejemplo impresión por transformación:
...
import
import
import
import
import
...
javax.xml.transform.TransformerFactory;
javax.xml.transform.Transformer;
javax.xml.transform.dom.DOMSource;
javax.xml.transform.stream.StreamResult;
java.io.FileOutputStream;
try {
DOMSource source = new DOMSource(newdoc);
StreamResult result =
new StreamResult(new FileOutputStream("processed.xml"));
TransformerFactory transFactory =
TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, result);
} catch (Exception e){
e.printStackTrace();
}
Imprimir árbol (III)

La tercera alternativa es utilizar un XMLSerializer de la API de Apache, que permite dar formato a la salida, como los espacios
de indentación, si se imprimirá la cabecera xml, etc.
...
// Para serializar
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serialize.DOMSerializer;
import java.io.StringWriter;
...
//Paso 3: Insertamos nuevos nodos
insertResult(doc, root, suma);
...
static void printDocument(Document doc) throws Exception {
OutputFormat outputOptions = new OutputFormat();
outputOptions.setOmitXMLDeclaration(true);
outputOptions.setIndent( 4 );
outputOptions.setMethod( "xml" );
StringWriter output = new StringWriter();
DOMSerializer serializer = new XMLSerializer(output, outputOptions);
serializer.serialize(doc);
System.out.print(output.getBuffer());
}
Ejercicios

Se puede profundizar más en la práctica



Insertando el resultado en otra parte del
documento
Computando datos desde atributos
Insertando atributos en vez de elementos