hibernate-orm/reference/es/modules/xml.xml

283 lines
9.7 KiB
XML

<chapter id="xml">
<title>Mapeo XML</title>
<para><emphasis>
Nota que esta es una funcionalidad experimental en Hibernate 3.0 y está
bajo un desarrollo extremadamente activo.
</emphasis></para>
<sect1 id="xml-intro" revision="1">
<title>Trabajando con datos XML</title>
<para>
Hibernate te permite trabajar con datos XML persistentes en casi la misma forma
que trabajas con POJOs persistentes. Un árbol XML analizado (parsed) puede ser
pensado como sólo otra forma de representar los datos relacionales a nivel de objetos,
en vez de POJOs.
</para>
<para>
Hibernate soporta dom4j como API para manipular árboles XML. Puedes escribir
consultas que traigan árboles dom4j de la base de datos y tener cualquier modificación
que hagas al árbol sincronizada automáticamente a la base de datos. Puedes incluso tomar
un documento XML, analizarlo usando dom4j, y escribirlo a la base de datos con cualquiera
de las operaciones básicas de Hibernate: <literal>persist(), saveOrUpdate(), merge(),
delete(), replicate()</literal> (la fusión no está aún soportada).
</para>
<para>
Esta funcionalidad tiene muchas aplicaciones incluyendo la importación/exportación de datos,
externalización de datos de entidad vía JMS o SOAP y reportes basados en XSLT.
</para>
<para>
Un solo mapeo puede ser usado 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, puede ser usado para mapear sólo
el XML.
</para>
<sect2 id="xml-intro-mapping">
<title>Especificando los mapeos de XML y de clase juntos</title>
<para>
He aquí un ejemplo de mapear un POJO y XML simultáneamente:
</para>
<programlisting><![CDATA[<class name="Account"
table="ACCOUNTS"
node="account">
<id name="accountId"
column="ACCOUNT_ID"
node="@id"/>
<many-to-one name="customer"
column="CUSTOMER_ID"
node="customer/@id"
embed-xml="false"/>
<property name="balance"
column="BALANCE"
node="balance"/>
...
</class>]]></programlisting>
</sect2>
<sect2 id="xml-onlyxml">
<title>Especificando sólo un mapeo XML</title>
<para>
He aquí un ejemplo donde no hay ninguna clase POJO:
</para>
<programlisting><![CDATA[<class entity-name="Account"
table="ACCOUNTS"
node="account">
<id name="id"
column="ACCOUNT_ID"
node="@id"
type="string"/>
<many-to-one name="customerId"
column="CUSTOMER_ID"
node="customer/@id"
embed-xml="false"
entity-name="Customer"/>
<property name="balance"
column="BALANCE"
node="balance"
type="big_decimal"/>
...
</class>]]></programlisting>
<para>
Este mapeo te permite acceder a los datos como un árbol dom4j, o como un grafo de pares nombre/valor de
propiedad (<literal>Map</literal>s de Java). Los nombres de propiedades son construcciones puramente
lógicas a las que se puede hacer referencia en consultas HQL.
</para>
</sect2>
</sect1>
<sect1 id="xml-mapping" revision="1">
<title>Mapeo de metadatos XML</title>
<para>
Muchos elementos de mapeo de Hibernate aceptan el atributo <literal>node</literal>. Esto te permite espcificar
el nombre de un atributo o elemento XML que contenga los datos de la propiedad o entidad. El formato del
atributo <literal>node</literal> debe ser uno de los siguientes:
</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>"element-name"</literal> - mapea al elemento XML mencionado</para>
</listitem>
<listitem>
<para><literal>"@attribute-name"</literal> - mapea al atributo XML mencionado</para>
</listitem>
<listitem>
<para><literal>"."</literal> - mapea al elemento padre</para>
</listitem>
<listitem>
<para>
<literal>"element-name/@attribute-name"</literal> -
mapea al atributo mencionado del elemento mencionado
</para>
</listitem>
</itemizedlist>
<para>
Para las colecciones y asociaciones monovaluadas, existe un atributo adicional <literal>embed-xml</literal>.
Si <literal>embed-xml="true"</literal>, que es el valor por defecto, el árbol XML para la entidad
asociada (o colección de tipo de valor) será embebida directamente en el árbol XML para la entidad que
posee la asociación. En otro caso, si <literal>embed-xml="false"</literal>, sólo el valor identificador
referenciado aparecerá en el XML para asociaciones de punto único y para las colecciones simplemente
no aparecerá en absoluto.
</para>
<para>
¡Debes ser cuidadoso de no dejar <literal>embed-xml="true"</literal> para demasiadas asociaciones,
ya que XML no trata bien la circularidad!
</para>
<programlisting><![CDATA[<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>]]></programlisting>
<para>
en este caso, hemos decidido embeber la colección de ids de cuenta, pero no los datos reales de cuenta.
La siguiente consulta HQL:
</para>
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
<para>
devolvería conjuntos de datos como estos:
</para>
<programlisting><![CDATA[<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>]]></programlisting>
<para>
Si estableces <literal>embed-xml="true"</literal> en el mapeo <literal>&lt;one-to-many&gt;</literal>, los datos
podrían verse así:
</para>
<programlisting><![CDATA[<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>]]></programlisting>
</sect1>
<sect1 id="xml-manipulation" revision="1">
<title>Manipulando datos XML</title>
<para>
Vamos a releer y actualizar documentos XML en la aplicación. Hacemos esto obteniendo una sesión dom4j:
</para>
<programlisting><![CDATA[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();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
<para>
Es extremadamente útil combinar esta funcionalidad con la operación <literal>replicate()</literal>
de Hibernate para implementar la importación/exportación de datos basada en XML.
</para>
</sect1>
</chapter>