2009-11-21 2 views
18

Проблема, с которой я столкнулся, заключается в том, как упорядочить большой список объектов в один XML-файл, поэтому я не могу сортировать полный список за один шаг. У меня есть метод, который возвращает эти объекты в кусках, но затем я сортирую их с помощью JAXB, маршаллер возвращается с исключением, что эти объекты не являются корневыми элементами. Это нормально для нормального случая, когда вы хотите собрать весь документ за один шаг, но это также произойдет, если я установил для свойства JAXB_FRAGMENT значение true.Как передавать большие файлы с помощью JAXB Marshaller?

Это желаемый результат XML:

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

Так что я полагаю, мне нужно какое-то слушатель, который динамически загружает следующий фрагмент repeatingElements кормить его к ИАС, прежде чем он будет писать закрывающий тег из RootElement. Но как это сделать? До сих пор я использовал JAXB для сортировки небольших файлов, и в документации JAXB не было много намеков на этот случай использования.

ответ

-8

Я не знаю много JAXB, поэтому я не могу помочь. Но если вы не возражаете, у меня есть предложение.

Написание XML намного проще, чем чтение, поэтому решение проблемы может заключаться в использовании более «низкоуровневого» подхода. Просто напишите свой собственный маршаллер, используя одну из доступных библиотек с открытым исходным кодом для XML. Я думаю, вы можете легко делать то, что хотите, используя dom4j.

9

Как вы обнаружили, если класс не имеет аннотации @XmlRootElement, то вы не можете передать экземпляр этого класса маршаллеру. Тем не менее, есть простой способ обойти это: оберните объект в JAXBElement и передайте его маршаллеру.

JAXBElement - довольно неуклюжий зверь, но то, что он делает, содержит имя элемента и пространство имен объекта, который вы хотите маршалировать, информацию, которая обычно содержится в аннотации @XmlRootElement. До тех пор, пока у вас есть имя и пространство имен, вы можете построить JAXBElement, чтобы обернуть свой POJO и маршалировать это.

Если ваши POJO были сгенерированы XJC, тогда он также сгенерировал класс ObjectFactory, который содержит заводские методы для создания оберток JAXBElement, что делает вещи немного проще.

Вам все равно придется использовать свойство JAXB_FRAGMENT для повторяющихся внутренних элементов, в противном случае JAXB будет генерировать такие вещи, как пролог XML, каждый раз, чего вы не хотите.

15

Я знаю, что это старый вопрос, но я наткнулся на него, ища дубликаты другого подобного вопроса.

Как предлагает @skaffman, вы хотите маршала с включенным JAXB_FRAGMENT и вашими объектами, завернутыми в JAXBElement. Затем вы неоднократно маршалируете каждый отдельный экземпляр повторяющегося элемента. В принципе, похоже, что вы хотите примерно примерно так:

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

Необходимо установить маршаллера в конструкторе. this.marshaller = м; –

Смежные вопросы