Leer y escribir XML en Java

    驴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:

    <?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:

    <?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!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *