Hibernate.orgCommunity Documentation

Capítulo 18. Mapeamento XML

18.1. Trabalhando com dados em XML
18.1.1. Especificando o mapeamento de uma classe e de um arquivo XML simultaneamente
18.1.2. Especificando somente um mapeamento XML
18.2. Mapeando metadados com XML
18.3. Manipulando dados em XML

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

Hibernate allows you to work with persistent XML data in much the same way you work with persistent POJOs. A parsed XML tree can be thought of as another way of representing the relational data at the object level, instead of POJOs.

O Hibernate suporta a API dom4j para manipular árvores XML. Você pode escrever queries que retornem árvores dom4j do banco de dados e automaticamente sincronizar com o banco de dados qualquer modificação feita nessas árvores. Você pode até mesmo pegar um documento XML, parsear usando o dom4j, e escrever as alterações no banco de dados usando quaisquer operações básicas do Hibernate: persist(), saveOrUpdate(),merge(), delete(), replicate() (merging ainda não é suportado)

Essa funcionalidade tem várias aplicações incluindo importação/exportação de dados, externalização de dados de entidade via JMS or SOAP e relatórios usando XSLT.

A single mapping can be used to simultaneously map properties of a class and nodes of an XML document to the database, or, if there is no class to map, it can be used to map just the XML.

A range of Hibernate mapping elements accept the node attribute. This lets you specify the name of an XML attribute or element that holds the property or entity data. The format of the node attribute must be one of the following:

For collections and single valued associations, there is an additional embed-xml attribute. If embed-xml="true", the default, the XML tree for the associated entity (or collection of value type) will be embedded directly in the XML tree for the entity that owns the association. Otherwise, if embed-xml="false", then only the referenced identifier value will appear in the XML for single point associations and collections will not appear at all.

Do not leave embed-xml="true" for too many associations, since XML does not deal well with circularity.

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

In this case, the collection of account ids is embedded, but not the actual account data. The following HQL query:

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

would return datasets such as this:

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

Se você setar embed-xml="true" em um mapeamento <one-to-many>, os dados se pareceriam com o seguinte:

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

You can also re-read and update XML documents in the application. You can do this by obtaining a dom4j session:

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();

When implementing XML-based data import/export, it is useful to combine this feature with Hibernate's replicate() operation.