¿Qué es XML?
La abreviatura «XML» significa – eXtensible METROArkup Language. Tiene una estructura de marcado similar a HTML y fue diseñado para almacenar y transportar datos. Define un conjunto de reglas que lo hacen legible tanto por humanos como por máquinas.
A pesar de ser un lenguaje de marcado como HTML, XML se usa comúnmente para intercambiar datos entre servicios web, backends y front-end, al igual que JSON y se considera su predecesor.
Si está interesado en leer y escribir JSON en Java, ¡ya lo tenemos cubierto!
Es importante tener en cuenta que XML no tiene un conjunto predefinido de etiquetas como HTML, sino que están definidas por el usuario. Es esta flexibilidad la que llevó a la creación de múltiples formatos de documentos como RSS, Atom, SOAP y XHTML. Todos estos formatos son subconjuntos de XML, en esencia.
Veamos un documento XML simple, que replica el mismo objeto que usamos anteriormente con respecto a JSON:
Te puede interesar:Java convertir entero en cadena<?xml version="1.0" encoding="UTF-8"?>
<person>
<age>31</age>
<hobbies>
<element>Football</element>
<element>Swimming</element>
</hobbies>
<isMarried>true</isMarried>
<kids>
<person>
<age>5</age>
<name>Billy</name>
</person>
<person>
<age>3</age>
<name>Milly</name>
</person>
</kids>
<name>Benjamin Watson</name>
</person>
La diferencia clave entre XML y JSON es que estamos definiendo este archivo con la versión XML y codificando al principio del documento con una <?xml>
etiqueta. Otra diferencia es que cada propiedad del objeto debe estar envuelta en su propia etiqueta: <age>31</age>
. Los elementos de la matriz no se pueden especificar sin una etiqueta, por lo tanto, para enumerarlos, los terminamos con <element>...</element>
dentro de <hobbies>...</hobbies>
etiqueta.
JAXB
Como XML es un formato basado en texto, puede utilizar las mismas técnicas para leerlo y escribirlo que cualquier otro archivo de texto.
Java, sin embargo, proporciona una forma conveniente de manipular XML utilizando el marco llamado Java UNarquitectura para XML segundoinding, o JAXB para abreviar. Nos permite mapear objetos Java a documentos XML y viceversa. JAXB se introdujo por primera vez en JDK 1.6 y no está disponible en versiones anteriores.
Como JAXB es un marco JDK estándar, no es necesario incluir dependencias externas al proyecto para JDK 1.6+.
Nota: Sin embargo, si está utilizando Java 9 o superior, debe incluir un parámetro adicional al javac
mando. Si está utilizando un IDE como IntelliJ IDEA o Eclipse, busque una configuración de opciones del compilador adicional y asegúrese de que incluya el --add-modules java.xml.bind
String.
En el caso de IntelliJ IDEA, se encuentra en Preferences
-> Build, Execution, Deployment
-> Compiler
-> Java Compiler
menú.
Si aún recibes errores como Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBContext
incluso después de agregar la opción de compilador adicional, agregue las siguientes dependencias de Maven:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
Los conceptos básicos de JAXB se nombran Marshalling y Desarmado. Están, como era de esperar, representados por las clases Marshaller
y Unmarshaller
.
Marshalling es el proceso de convertir objetos Java en XML y Unmarshalling es el proceso de convertir XML en objetos Java.
JAXB se configura mediante anotaciones que se importan del javax.xml.bind.annotations
paquete.
Definamos una clase Java que represente a la persona descrita en nuestro documento XML:
@XmlRootElement
public class Person {
public Person(String name, int age, boolean isMarried, List<String> hobbies, List<Person> kids) {
this.name = name;
this.age = age;
this.isMarried = isMarried;
this.hobbies = hobbies;
this.kids = kids;
}
public Person(String name, int age) {
this(name, age, false, null, null);
}
private String name;
private Integer age;
private Boolean isMarried;
private List<String> hobbies;
private List<Person> kids;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isMarried() {
return isMarried;
}
@XmlElement(name = "isMarried")
public void setMarried(boolean married) {
isMarried = married;
}
@XmlElementWrapper(name = "hobbies")
@XmlElement(name = "element")
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public List<Person> getKids() {
return kids;
}
@XmlElementWrapper(name = "kids")
@XmlElement(name = "person")
public void setKids(List<Person> kids) {
this.kids = kids;
}
@Override
public String toString() {
return "Person{" +
"name="" + name + "'' +
", age=" + age +
", isMarried=" + isMarried +
", hobbies=" + hobbies +
", kids=" + kids +
'}';
}
}
@XmlRootElement
– asigna una clase o un tipo de enumeración a un elemento XML. Describe el elemento raíz del documento XML y debe especificarse en el Person
declaración de clase.
@XmlElementWrapper
– genera un elemento contenedor alrededor de la representación XML, un List
en nuestro caso. Los elementos de la lista deben especificarse explícitamente utilizando el @XMLElement
anotación.
@XMLElement
– asigna una propiedad de un objeto Java a un elemento XML derivado del nombre de la propiedad. Para especificar un nombre de propiedad XML diferente, lo incluimos como un parámetro de cadena en la declaración de anotación, es decir (name = "person")
.
Desagrupamiento
El ejemplo más simple de la técnica de clasificación requerirá que creemos un JAXBContext
ejemplo, pasando un Person.class
como el único parámetro de entrada de su constructor.
El unmarshaller se crea luego llamando a un createUnmarshaller()
método, y una instancia del actual Person
es generado por su unmarshal()
método.
Asegúrate de utilizar un encasillado explícito, como unmarshal
método devuelve el tipo de objeto:
public class Solution {
public static void main(String[] args) throws Exception {
Person person = XMLtoPersonExample("person.xml");
System.out.println(person);
}
private static Person XMLtoPersonExample(String filename) throws Exception {
File file = new File(filename);
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return (Person) jaxbUnmarshaller.unmarshal(file);
}
}
Después de ejecutar este código, debería ver algo como:
Person{name="Benjamin Watson", age=31, isMarried=true, hobbies=[Football, Swimming], kids=[Person{name="Billy", age=5, isMarried=null, hobbies=null, kids=null}, Person{name="Milly", age=3, isMarried=null, hobbies=null, kids=null}]}
Marshalling
Para demostrar la capacidad de JAXB para escribir un archivo XML utilizando el objeto Java como fuente, agregaremos el siguiente método:
private static void personToXMLExample(String filename, Person person) throws Exception {
File file = new File(filename);
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(person, file);
jaxbMarshaller.marshal(person, System.out);
}
Es muy similar al ejemplo anterior e incluye la creación de un JAXBContext
de nuevo. Esta vez, sin embargo, el proceso irá en la dirección inversa y la salida XML se escribirá en el archivo y la consola.
Al agregar una invocación de este método como última cadena en el Solution.main()
me gusta:
personToXMLExample("person-output.xml", person);
y ejecutándolo, obtendremos una desafortunada excepción.
Exception in thread "main" java.lang.NullPointerException
at com.Pharos.sh.xml.Person.isMarried(Person.java:49)
at com.Pharos.sh.xml.Person$JaxbAccessorM_isMarried_setMarried_boolean.get(MethodAccessor_Boolean.java:61)
...
Hemos cometido un error al configurar el isMarried
tipo de campo a la clase contenedora Boolean
y el tipo de retorno del getter isMarried()
a primitivo boolean
, lo que lleva a JAXB a intentar desempaquetar null
y lanzando un NullPointerException
como resultado de ello.
Una solución rápida y fácil para esto sería alinear esos dos con boolean
o Boolean
.
Después de solucionar el problema, obtendremos el siguiente resultado tanto en la consola como en el archivo:
Te puede interesar:Spring Security: registro de verificación de correo electrónico<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<age>31</age>
<hobbies>
<element>Football</element>
<element>Swimming</element>
</hobbies>
<kids>
<person>
<age>5</age>
<name>Billy</name>
</person>
<person>
<age>3</age>
<name>Milly</name>
</person>
</kids>
<isMarried>true</isMarried>
<name>Benjamin Watson</name>
</person>
Como vemos, es completamente idéntico al archivo XML original que clasificamos en el person
objeto.
Conclusión
La lectura y escritura de XML en Java se puede realizar fácilmente utilizando el marco JAXB. Usando anotaciones, definimos las reglas de mapeo entre clases Java y documentos XML que representan sus objetos.
XML a menudo se considera un formato desactualizado que es inferior a JSON. Sin embargo, saber cómo leerlo y escribirlo usando Java es una habilidad útil para cualquier desarrollador de software, ya que muchos de los servicios en la web todavía lo usan y aún no tienen una API JSON. Este también es el caso de muchos formatos de archivo que almacenan datos en archivos con formato XML.
Aunque, en caso de que JSON sea más lo tuyo, te sugiero que leas sobre cómo leer y escribir JSON en Java, ¡también lo cubrimos!