Construyendo XML en Java: desde DOM hasta JAXB
Cuando comencé a trabajar con XML en Java, una de las primeras alternativas que utilicé fue la API DOM incluida en Java. En ese momento desconocía JAXB, por lo que construir un documento XML significaba crear explícitamente cada elemento y agregarlo al árbol del documento.
Con el tiempo conocí JAXB y una forma bastante diferente de enfrentar el mismo problema: representar la estructura XML mediante objetos Java y dejar que una biblioteca realice la transformación.
En esta entrada veremos ambas alternativas y las diferencias que existen entre ellas.
El XML que queremos construir
Utilizaremos un ejemplo sencillo:
<?xml version="1.0" encoding="UTF-8"?>
<Producto>
<Codigo>1001</Codigo>
<Nombre>Teclado USB</Nombre>
<Precio>15990</Precio>
</Producto>
Nuestro objetivo será generar este documento desde una aplicación Java.
1. Construcción utilizando DOM
Java dispone de una API estándar para manipular documentos XML mediante el modelo DOM (Document Object Model).
DOM representa un documento XML como un árbol de nodos.
En nuestro ejemplo podemos imaginarlo de la siguiente manera:
Producto
├── Codigo
├── Nombre
└── Precio
Para construirlo utilizaremos principalmente clases de:
org.w3c.dom
javax.xml.parsers
Primero creamos el documento:
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder =
factory.newDocumentBuilder();
Document document =
builder.newDocument();
Ahora podemos crear el elemento raíz:
Element producto =
document.createElement("Producto");
document.appendChild(producto);
Después agregamos cada uno de sus elementos.
Element codigo =
document.createElement("Codigo");
codigo.appendChild(
document.createTextNode("1001")
);
producto.appendChild(codigo);
Repetimos el procedimiento para los demás datos:
Element nombre =
document.createElement("Nombre");
nombre.appendChild(
document.createTextNode("Teclado USB")
);
producto.appendChild(nombre);
Element precio =
document.createElement("Precio");
precio.appendChild(
document.createTextNode("15990")
);
producto.appendChild(precio);
Finalmente necesitamos transformar el árbol DOM en XML.
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
transformer.setOutputProperty(
OutputKeys.INDENT,
"yes"
);
DOMSource source =
new DOMSource(document);
StreamResult result =
new StreamResult(System.out);
transformer.transform(source, result);
El resultado será nuestro documento XML.
¿Qué estamos haciendo realmente?
Cuando trabajamos directamente con DOM somos nosotros quienes construimos la estructura del documento.
Creamos:
el
Document;el elemento raíz;
cada elemento hijo;
los nodos de texto;
los atributos, cuando existen;
y finalmente transformamos el árbol para obtener el XML.
Esto entrega bastante control, pero también genera código repetitivo cuando los documentos empiezan a crecer.
2. Separando nuestros datos del XML
Supongamos ahora que nuestra aplicación ya tiene una clase Producto.
public class Producto {
private String codigo;
private String nombre;
private BigDecimal precio;
// getters y setters
}
Esta clase representa nuestro modelo de datos.
Aquí aparece una pregunta interesante:
¿Por qué construir manualmente cada elemento XML si la información ya está representada mediante objetos Java?
Precisamente este es uno de los problemas que JAXB permite resolver.
3. Construcción utilizando JAXB
JAXB significa Java Architecture for XML Binding.
A diferencia del ejemplo anterior, ahora no vamos a construir directamente cada nodo del documento.
Vamos a definir cómo nuestro objeto Java debe representarse como XML.
En Java moderno podemos utilizar las anotaciones de Jakarta XML Binding.
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Producto")
public class Producto {
private String codigo;
private String nombre;
private BigDecimal precio;
@XmlElement(name = "Codigo")
public String getCodigo() {
return codigo;
}
public void setCodigo(String codigo) {
this.codigo = codigo;
}
@XmlElement(name = "Nombre")
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
@XmlElement(name = "Precio")
public BigDecimal getPrecio() {
return precio;
}
public void setPrecio(BigDecimal precio) {
this.precio = precio;
}
}
Ahora creamos normalmente nuestro objeto:
Producto producto = new Producto();
producto.setCodigo("1001");
producto.setNombre("Teclado USB");
producto.setPrecio(
new BigDecimal("15990")
);
Después creamos el contexto JAXB:
JAXBContext context =
JAXBContext.newInstance(Producto.class);
Y obtenemos un Marshaller:
Marshaller marshaller =
context.createMarshaller();
marshaller.setProperty(
Marshaller.JAXB_FORMATTED_OUTPUT,
true
);
Finalmente:
marshaller.marshal(
producto,
System.out
);
JAXB se encarga de transformar el objeto Java en XML.
4. Dos maneras diferentes de pensar el problema
Esta es probablemente la diferencia más importante.
Cuando utilizamos DOM pensamos directamente en la estructura XML:
crear Documento
↓
crear Producto
↓
crear Codigo
↓
crear Nombre
↓
crear Precio
↓
generar XML
Con JAXB pensamos principalmente en nuestro modelo:
Producto
↓
codigo
nombre
precio
↓
Marshaller
↓
XML
En otras palabras:
DOM
Datos
↓
Construcción manual del árbol XML
↓
XML
JAXB
Objetos Java
↓
Mapeo objeto/XML
↓
XML
JAXB introduce una capa de abstracción que evita tener que construir manualmente buena parte del árbol XML.
5. ¿Entonces JAXB reemplaza a DOM?
No necesariamente.
Son herramientas que permiten abordar XML desde niveles diferentes.
DOM resulta útil cuando necesitamos manipular directamente la estructura del documento, crear nodos dinámicamente o tener un control muy explícito sobre el XML que estamos construyendo.
JAXB resulta especialmente cómodo cuando existe una correspondencia clara entre nuestro modelo de objetos y la estructura XML.
Por ejemplo, si tenemos:
Documento
├── Encabezado
│ ├── Emisor
│ └── Receptor
│
└── Detalle
├── Item
├── Item
└── Item
podemos representar esa misma estructura mediante clases:
Documento
├── Encabezado
│ ├── Emisor
│ └── Receptor
│
└── List<Item>
En ese escenario JAXB puede reducir considerablemente el código necesario para generar el XML.
6. ¿Y qué ocurre con un XSD?
En aplicaciones reales muchas veces no basta con producir un XML bien formado.
El documento además debe cumplir una estructura determinada.
Para eso existen los esquemas XML o XSD.
Podemos tener entonces un proceso como:
Datos
↓
Objetos Java
↓
Generación XML
↓
Validación XSD
↓
XML válido
La generación y la validación son problemas relacionados, pero diferentes.
Podemos generar perfectamente un XML que sea sintácticamente correcto y que, sin embargo, no cumpla con el esquema requerido por otro sistema.
Por eso, cuando trabajamos con integraciones basadas en XML, resulta conveniente validar el documento antes de enviarlo.
En Java podemos hacerlo utilizando SchemaFactory y Validator.
Por ejemplo:
SchemaFactory factory =
SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI
);
Schema schema =
factory.newSchema(
new File("producto.xsd")
);
Validator validator =
schema.newValidator();
validator.validate(
new StreamSource(
new File("producto.xml")
)
);
Si el documento no cumple con el esquema, la validación lanzará una excepción.
7. DOM vs JAXB
Podemos resumir las diferencias principales de esta forma:
| DOM | JAXB |
|---|---|
| Trabaja directamente con el árbol XML | Trabaja principalmente con objetos Java |
| Creamos elementos manualmente | El XML se obtiene mediante marshalling |
| Mucho control sobre la estructura | Mayor abstracción |
| Puede producir bastante código repetitivo | Reduce código de construcción |
| Conveniente para manipulación dinámica | Conveniente para modelos estructurados |
| Forma parte de las APIs XML tradicionales de Java | En Java moderno normalmente se agrega como dependencia |
Ninguna de las dos aproximaciones es universalmente mejor.
La elección depende principalmente de qué necesitamos hacer con el XML.
8. Algo que aprendí trabajando con XML
Cuando comencé a construir documentos XML en Java lo hice directamente mediante DOM porque desconocía JAXB.
Visto años después, no considero que haya sido tiempo perdido.
Trabajar directamente con DOM permite comprender qué ocurre realmente dentro de un documento XML: elementos, nodos, atributos, jerarquías y relaciones padre-hijo.
Después, al conocer JAXB, resulta mucho más sencillo comprender qué problema está resolviendo.
JAXB no hace desaparecer XML.
Lo que hace es entregarnos una abstracción para transformar nuestros objetos Java en una representación XML sin tener que construir manualmente cada uno de sus nodos.
Por eso conocer ambas aproximaciones sigue siendo útil.
Primero podemos entender cómo está construido el documento.
Después podemos decidir cuánto de ese trabajo queremos delegar a una biblioteca.
Comentarios
Publicar un comentario