2012-03-13 15 views
20

Tengo una aplicación que hace XML < -> conversiones utilizando Jaxb y clases generadas automáticamente con maven-jaxb2-plugin.Jaxb: cómo unmarshall xs: cualquier parte de cadena XML?

En alguna parte de mi esquema, tengo la posibilidad de ingresar "CUALQUIER" xml.

Actualización: esto describe mejor mi esquema. Algunos XML conocidos envuelven una parte totalmente desconocida (la parte "cualquier").

<xs:complexType name="MessageType"> 
    <xs:sequence> 
    <xs:element name="XmlAnyPayload" minOccurs="0"> 
     <xs:complexType> 
      <xs:sequence> 
       <xs:any namespace="##any"/> 
      </xs:sequence> 
     </xs:complexType> 
    </xs:element> 
    <xs:element name="OtherElements"> 
     .... 
</xs:sequence> 

Este mapas (por jaxb) a una clase interna como este.

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "", propOrder = { 
    "any" 
}) 
public static class XmlAnyPayload { 

    @XmlAnyElement(lax = true) 
    protected Object any; 

Cuando deshago toda la estructura, no hay problema. El "Object any" se convertirá en un org.apache.xerces.dom.ElementNSImpl. Ahora, quiero recrear el objeto Java manualmente y luego ir a XML. ¿Cómo tomo un XML aleatorio y lo coloco en el elemento any (org.apache.xerces.dom.ElementNSImpl) para poder construir el objeto Java?

Además, el siguiente caso es cuando tengo este elemento como java, quiero deshacer esta misma parte (para poder extraer la cadena XML de este elemento). Pero esto no es posible. Obtengo una excepción sobre los elementos raíz. Pero no es posible anotar ElementNSImpl.

unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an @XmlRootElement annotation 

¿Tiene alguna sugerencia sobre cómo manejar estos problemas?

+0

Gracias a una buena entrada en este dominio, me las arreglé para resolver esto. De una manera, me quedé con mi nodo Dom. Acabo de agregar un análisis XML simple para obtener el dom de la cadena. Por otro lado, recurrí a trabajar con el XML en el espacio DOM (XPATH sabio), ya que realmente me ahorró tiempo y cambios de contexto. XPATH es realmente bueno para mantener baja la complejidad del código. –

Respuesta

37

@XmlAnyElement(lax = true) significa en la llanura Inglés algo así como:

Estimado JAXB! Si tiene un mapeo para este elemento, descomprímalo en un objeto Java. Si no conoce este elemento, simplemente déjelo como un elemento DOM .

Esto es exactamente lo que está sucediendo en su caso. Por lo tanto, si realmente desea desglosar el contenido de este lax, proporcione al contexto JAXB una asignación para el elemento que desea desvincular.La forma más sencilla de hacer esto es para anotar su clase con @XmlRootElement

@XmlRootElement(name="foo", namespace="urn:bar") 
public class MyClass { ... } 

Ahora cuando se crea el contexto JAXB, añadir MyClass en él:

JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class); 

En este caso, si JAXB se encuentra con el elemento de {urn:bar}foo en el lugar de ese xs:any, sabrá que este elemento está mapeado en MyClass y tratará de deshacer MyClass.

Si está creando un contexto JAXB basado en el nombre del paquete (probablemente sí), puede agregarle la clase (por ejemplo, com.acme.foo.MyClass). La forma más fácil es crear un recurso com/acme/foo/jaxb.index:

com.acme.foo.MyClass 

Y el paquete de agregar su nombre a la ruta de contexto:

JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo"); 

Hay otras maneras con ObjectFactory etc., pero el truco es con jaxb.index probablemente el más fácil.

Como alternativa, en lugar de unmarshalling todo en una carrera, puede dejar el contenido de xs:any como DOM y deserializar en el objeto de destino en un segundo unmarshalling con anothe contexto JAXB (que sabe la clase de MyClass). Algo así como:

JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class); 
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny()); 

Este enfoque es a veces mejor, sobre todo cuando se tiene una combinación de esquemas de contenedores/carga útil que son relativamente independientes. Depende del caso.

Todo lo dicho anteriormente se aplica también a la clasificación. Todo es prolijamente bidireccional.

+2

Esta respuesta fue un salvavidas. Huelga decir que lo voté, lo siento no puedo hacerlo dos veces. Una excelente explicación más una buena solución. ¡Gracias, lexicore! – quantum

+2

@Quantum De nada. Salvar vidas se volvió un poco más fácil. :) – lexicore

+0

@lexicore Entonces, si XmlAnyElement se establece en falso/omitido, ¿lo dejará como un objeto DOM? –

0
<xs:any/> 

requiere que algunas cosas no intuitivas se conviertan en objetos java. Si usted no tiene ninguna diferencia, trate de usar

<element name="any" type="xs:anyType"/> 
1

Creo que se necesita para este XSDs los "ninguna" parte y generar clases para ellos también.

Aquí hay más información:

http://jaxb.java.net/guide/Mapping_of__xs_any___.html

Editar: si su objeto que desea reunir no tiene la anotación @XmlRootElement (ver mensaje de error), entonces yo creo que hay que envolverlo con un JAXBElement.

+0

Gracias por su respuesta. Sin embargo, nunca sabré el contenido exacto de este "cualquiera" mensaje, ni quiero saber. Solo quiero ser capaz de manejarlo como un pedazo. –

+0

La guía vinculada proporciona algunos detalles interesantes sobre este dominio. –

Cuestiones relacionadas