2009-11-21 19 views
18

El problema al que me enfrento es cómo ordenar una gran lista de objetos en un solo archivo XML, por lo que no puedo ordenar la lista completa en un solo paso. Tengo un método que devuelve estos objetos en fragmentos, pero luego hago uso de estos JAXB, el marcador regresa con la excepción de que estos objetos no son elementos raíz. Esto está bien para el caso normal de que desee ordenar el documento completo en un solo paso, pero también ocurre si configuro la propiedad JAXB_FRAGMENT en verdadero.Cómo transmitir archivos grandes usando JAXB Marshaller?

Ésta es la salida XML deseada:

<rootElem> 
    <startDescription></startDescription> 
    <repeatingElem></repeatingElem> 
    <repeatingElem></repeatingElem>... 
</rootElem> 

así que supongo que necesito algún tipo de escucha que se carga dinámicamente el siguiente fragmento de repeatingElements para alimentar al contador de referencias antes de que él escribiría la etiqueta de cierre de la rootElement. Pero, ¿cómo hacer eso? Hasta ahora, solo utilizaba JAXB para ordenar archivos pequeños y la documentación de JAXB no da muchas pistas para ese caso de uso.

Respuesta

-8

No sé mucho de JAXB, así que no puedo ayudar. Pero si no te importa, tengo una sugerencia.

Escribir XML es mucho más fácil que leerlo, por lo que una solución para su problema podría ser utilizar un enfoque más "de bajo nivel". Simplemente escriba su propio marcador automático utilizando una de las bibliotecas de código abierto disponibles para XML. Creo que puedes hacer lo que quieras usando dom4j.

9

Como has descubierto, si una clase no tiene la anotación @XmlRootElement, entonces no puedes pasar una instancia de esa clase al marshaller. Sin embargo, hay una manera fácil de evitar esto: ajuste el objeto en un JAXBElement, y páselo al marshaller.

Ahora JAXBElement es una bestia bastante torpe, pero lo que hace es contener el nombre del elemento y el espacio de nombres del objeto que desea reunir, información que normalmente figuraría en la anotación @XmlRootElement. Siempre que tenga el nombre y el espacio de nombre, puede construir un JAXBElement para envolver su POJO y ordenarlo.

Si sus POJO fueron generados por XJC, entonces también habrá generado una clase ObjectFactory que contiene los métodos de fábrica para construir los contenedores JAXBElement, haciendo las cosas un poco más fáciles.

Igual tendrá que usar la propiedad JAXB_FRAGMENT para los elementos internos que se repiten, de lo contrario JAXB generará cosas como el prólogo XML cada vez, que no desea.

15

Soy consciente de que esta es una pregunta antigua pero me encontré con ella mientras buscaba duplicados de otra pregunta similar.

Como @skaffman sugiere, quiere utilizar Marshal con JAXB_FRAGMENT activado y sus objetos envueltos en JAXBElement. A continuación, dirige repetidamente cada instancia individual del elemento repetido. Básicamente, parece que quieres algo más o menos así:

public class StreamingMarshal<T> 
{ 
    private XMLStreamWriter xmlOut; 
    private Marshaller marshaller; 
    private final Class<T> type; 

    public StreamingMarshal(Class<T> type) throws JAXBException 
    { 
     this.type = type; 
     JAXBContext context = JAXBContext.newInstance(type); 
     Marshaller m = context.createMarshaller(); 
     m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); 
    } 

    public void open(String filename) throws XMLStreamException, IOException 
    { 
     xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream(filename)); 
     xmlOut.writeStartDocument(); 
     xmlOut.writeStartElement("rootElement"); 
    } 

    public void write(T t) throws JAXBException 
    { 
     JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(type.getSimpleName()), type, t); 
     marshaller.marshal(element, xmlOut); 
    } 

    public void close() throws XMLStreamException 
    { 
     xmlOut.writeEndDocument(); 
     xmlOut.close(); 
    } 
} 
+0

necesitas configurar marshaller en el constructor. this.marshaller = m; –

Cuestiones relacionadas