JAXB Parsing. XSD. XML Namespaces.

Нельзя обойти вниманием XML Parseer JAXB. Рассмотрим его работу на примере ручного описания и авто генерации классов.

Задание:
Parsing XML с помощью JAXB. Классы описать несколькими способами. Проработать пример с @XmlElementWrapper, с multi namespace.

Использовал:

JAXB XSD XML

Частая задача, работа с XML, поэтому решения которые позволяют решать задачи быстро очень интересны широкой публике и чаще всего используются при написании кода.

Основной принцип следующий: Получили в работу XML / либо сгенерировали XML.
– Необходимо по ней создать XSD схему. (Два варианта, ручной и автогенерация);
– По XSD сгенерировать JAXB классы описывающие элементы, либо описать вручную;
– Unmarshaller XML;

Для генерации XSD можно воспользоваться online генераторами, к примеру Freeformatter.

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="ActorCast">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Cast" maxOccurs="unbounded" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Character">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element type="xs:string" name="FirstName"/>
                                        <xs:element type="xs:string" name="LastName"/>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                            <xs:element name="Actor">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element type="xs:string" name="FirstName"/>
                                        <xs:element type="xs:string" name="LastName"/>
                                        <xs:element type="xs:string" name="BirthDay"/>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                        <xs:attribute type="xs:byte" name="id" use="optional"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Используя Idea Intellij и плагин WebService по XSD генерируем JAXB классы.

Ну и немного кода, Unmarshaller XML.

//Start Unmarshalling
JAXBContext jaxbContext = JAXBContext.newInstance(ActorCast.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ActorCast jaxbElement = (ActorCast) unmarshaller.unmarshal(new File(XMLFILE));
//Stop Unmarshalling
 
List<ActorCast.Cast> cast = jaxbElement.getCast();
 
for(ActorCast.Cast cst : cast){
	System.out.println("========================================");
	System.out.println("Actor: " +cst.getActor().getFirstName()+" "+cst.getActor().getLastName()+", "+cst.getActor().getBirthDay());
	System.out.println("Character: " +cst.getCharacter().getFirstName()+" "+cst.getCharacter().getLastName());
}

Для понимания процесса, теперь опишем модель XML вручную. Итак имеется XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ActorCast>
    <Cast id="1">
        <Character>
            <FirstName>Daenerys</FirstName>
            <LastName>Targaryen</LastName>
        </Character>
        <Actor>
            <FirstName>Emilia</FirstName>
            <LastName>Clarke</LastName>
            <BirthDay>23 October 1986</BirthDay>
        </Actor>
    </Cast>
</ActorCast>

По спецификации, XML наша содержит:
Root element– ActorCast. Он может быть только 1 в документе.
XML prolog

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

XML Elements – Cast, Character,FirstName …
XML Attribute – id. Значение атрибутов всегда должно заключаться в кавычки. И Value атрибута id равно 1.

Для каждой ноды XML в JAXB есть соответствующая аннотация.
Root element @XmlRootElement
XML Elements @XmlElement
XML Attribute @XmlAttribute

XML Tree

Добавилось несколько аннотаций:
@XmlAccessorType(XmlAccessType.FIELD) Доступ непосредственно к полям класса.
@Getter, @Setter, @ToString Аннотации от библиотеки lombok, код более читабелен, стандартные геттеры и сеттеры.

Не использовали еще одну полезную аннотацию: @XmlElementWrapper Указывает на то что, элемент является оберткой, в нашем случае по сути это элемент Cast.

Зачастую, рабочие XML не всегда выглядят так дружественно и имеют простую структуру, как в примере с Actors. Добавляется пространство имен – XML Namespaces. Основное предназначение Namespaces, избежание конфликтов наименований элементов.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ActorCast xmlns:ch="http://www.gotoqa.ru/character/"
           xmlns:ac="http://www.gotoqa.ru/actor/">
    <Cast id="1">
        <ch:Character>
            <ch:FirstName>Daenerys</ch:FirstName>
            <ch:LastName>Targaryen</ch:LastName>
        </ch:Character>
        <ac:Actor>
            <ac:FirstName>Emilia</ac:FirstName>
            <ac:LastName>Clarke</ac:LastName>
            <ac:BirthDay>23 October 1986</ac:BirthDay>
        </ac:Actor>
    </Cast>
</ActorCast>

Таким образом элементы области ch вне видимости в зоне ac и наоборот.
JAXB все аннотации имеют параметр namespace
@XmlRootElement(name = “ActorCast”, namespace = “http://www.gotoqa.ru/character/”)

Ссылка на полную версию проекта на GitHub:
Github JAXBParsingProject

Releated Post