Hibernate.orgCommunity Documentation

Capítulo 19. Mapeo XML

19.1. Trabajo con datos XML
19.1.1. Especificación de los mapeos de XML y de clase en conjunto
19.1.2. Especificación de sólo un mapeo XML
19.2. Mapeo de metadatos XML
19.3. Manipulación de datos XML

XML Mapping is an experimental feature in Hibernate 3.0 and is currently under active development.

Hibernate le permite trabajar con datos XML persistentes en casi de la misma forma que trabaja con POJOs persistentes. Un árbol XML analizado semáticamente se puede considerar como otra manera de representar los datos relacionales a nivel de objetos, en lugar de POJOs.

Hibernate soporta dom4j como API para manipular árboles XML. Puede escribir consultas que recuperen árboles dom4j de la base de datos y puede tener cualquier modificación que realice al árbol sincronizada automáticamente con la base de datos. Incluso puede tomar un documento XML, analizarlo sintácticamente utilizando dom4j, y escribirlo a la base de datos con cualquiera de las operaciones básicas de Hibernate: persist(), saveOrUpdate(), merge(), delete(), replicate() (merge aún no está soportado).

Esta funcionalidad tiene muchas aplicaciones incluyendo la importación/exportación de datos, externalización de datos de entidad por medio de JMS o SOAP y reportes basados en XSLT.

Un sólo mapeo se puede utilizar para mapear simultáneamente las propiedades de una clase y los nodos de un documento XML a la base de datos, o si no hay ninguna clase a mapear, se puede utilizar para mapear sólo el XML.

Muchos elementos de mapeo de Hibernate aceptan el atributo node. Esto le permite especificar el nombre de un atributo o elemento XML que contenga los datos de la propiedad o entidad. El formato del atributo node tiene que ser uno de los siguientes:

Para las colecciones y asociaciones monovaluadas, existe un atributo adicional embed-xml. Si embed-xml="true", el cual es el valor por defecto, el árbol XML para la entidad asociada (o colección de tipo de valor) será incluida directamente en el árbol XML para la entidad que posee la asociación. De otra manera, si embed-xml="false", entonces sólo el valor identificador referenciado aparecerá en el XML para asociaciones de punto único y para las colecciones simplemente no aparecerá.

No deje embed-xml="true" para demasiadas asociaciones ya que XML no se ocupa bien de la circularidad.


<class name="Customer"
        table="CUSTOMER" 
        node="customer">
        
    <id name="id" 
            column="CUST_ID" 
            node="@id"/>
            
    <map name="accounts" 
            node="." 
            embed-xml="true">
        <key column="CUSTOMER_ID" 
                not-null="true"/>
        <map-key column="SHORT_DESC" 
                node="@short-desc" 
                type="string"/>
        <one-to-many entity-name="Account"
                embed-xml="false" 
                node="account"/>
    </map>
    
    <component name="name" 
            node="name">
        <property name="firstName" 
                node="first-name"/>
        <property name="initial" 
                node="initial"/>
        <property name="lastName" 
                node="last-name"/>
    </component>
    
    ...
    
</class
>

En este caso, la colección de ids de cuenta están incluídos, pero no los datos reales de cuenta. La siguiente consulta HQL:

from Customer c left join fetch c.accounts where c.lastName like :lastName

retornaría conjuntos de datos como este:


<customer id="123456789">
    <account short-desc="Savings"
>987632567</account>
    <account short-desc="Credit Card"
>985612323</account>
    <name>
        <first-name
>Gavin</first-name>
        <initial
>A</initial>
        <last-name
>King</last-name>
    </name>
    ...
</customer
>

Si establece embed-xml="true" en el mapeo <one-to-many>, puede que los datos se vean así:


<customer id="123456789">
    <account id="987632567" short-desc="Savings">
        <customer id="123456789"/>
        <balance
>100.29</balance>
    </account>
    <account id="985612323" short-desc="Credit Card">
        <customer id="123456789"/>
        <balance
>-2370.34</balance>
    </account>
    <name>
        <first-name
>Gavin</first-name>
        <initial
>A</initial>
        <last-name
>King</last-name>
    </name>
    ...
</customer
>

Puede releer y actualizar documentos XML en la aplicación. Puede hacer esto obteniendo una sesión dom4j:

Document doc = ....;

       
Session session = factory.openSession();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Transaction tx = session.beginTransaction();
List results = dom4jSession
    .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
    .list();
for ( int i=0; i<results.size(); i++ ) {
    //add the customer data to the XML document
    Element customer = (Element) results.get(i);
    doc.add(customer);
}
tx.commit();
session.close();
Session session = factory.openSession();

Session dom4jSession = session.getSession(EntityMode.DOM4J);
Transaction tx = session.beginTransaction();
Element cust = (Element) dom4jSession.get("Customer", customerId);
for ( int i=0; i<results.size(); i++ ) {
    Element customer = (Element) results.get(i);
    //change the customer name in the XML and database
    Element name = customer.element("name");
    name.element("first-name").setText(firstName);
    name.element("initial").setText(initial);
    name.element("last-name").setText(lastName);
}
tx.commit();
session.close();

Es útil combinar esta funcionalidad con la operación replicate() de Hibernate para implementar la importación/exportación de datos basada en XML.