Как сделать маршал без пространства имен? - PullRequest
19 голосов
/ 12 мая 2010

У меня довольно большой повторяющийся XML для создания с использованием JAXB. Сохранение всего объекта в памяти, а затем маршалинг занимает слишком много памяти. По сути, мой XML выглядит так:

<Store>
  <item />
  <item />
  <item />
.....
</Store>

В настоящее время мое решение проблемы состоит в том, чтобы «жестко закодировать» корневой тег для выходного потока и последовательно маршалировать каждый из повторяющихся элементов:

aOutputStream.write("<?xml version="1.0"?>")
aOutputStream.write("<Store>")

foreach items as item
  aMarshaller.marshall(item, aOutputStream)
end
aOutputStream.write("</Store>")
aOutputStream.close()

Каким-то образом JAXB генерирует XML, как это

 <Store  xmlns="http://stackoverflow.com">
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
.....
</Store>

Хотя это допустимый XML, но выглядит он просто уродливо, поэтому мне интересно, есть ли способ сказать маршаллеру не помещать пространство имен для элементов item? Или есть лучший способ использовать JAXB для сериализации в чанк XML по чанку?

Ответы [ 7 ]

12 голосов
/ 12 мая 2010

Проверьте ваш package-info.java (в пакете, где находятся ваши аннотированные jaxb классы). Там есть namespace атрибут @XmlSchema.

Кроме того, в аннотации @XmlRootElement есть атрибут namespace.

8 голосов
/ 08 апреля 2011

Следующие действия помогли мне:

         XMLStreamWriter writer = ...
         writer.setNamespaceContext(new NamespaceContext() {
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }

            public String getPrefix(String namespaceURI) {
                return "";
            }

            public String getNamespaceURI(String prefix) {
                return null;
            }
        });
7 голосов
/ 10 ноября 2011

Существует очень простой способ избавиться от префиксов пространства имен в вашем случае: просто установите атрибут elementFormDefault в unqualified в вашей схеме, например:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:your="http://www.stackoverflow.com/your/namespace">

Префикс пространства имен вы получите только в первом теге:

<ns1:your xmlns:ns1="http://www.stackoverflow.com/your/namespace">

Надеюсь, это поможет.

С уважением Павел Процай

6 голосов
/ 29 июня 2016

Я перепробовал все решения, представленные здесь, и ни одно из них не подошло для моей среды Мои текущие требования:

  1. jdk1.6.0_45
  2. JAXB-аннотированные классы генерируются при каждой перестройке, поэтому изменять их нельзя.

Я хотел бы поделиться с вами результатами моих экспериментов с решениями, которые я нашел в stackoverflow.

Пользовательский NamespaceContext ссылка

Простое и элегантное решение, но в моей среде у меня есть исключение со следующей трассировкой стека:

javax.xml.stream.XMLStreamException: Trying to write END_DOCUMENT when document has no root (ie. trying to output empty document).

at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1473)
at com.ctc.wstx.sw.BaseStreamWriter.reportNwfStructure(BaseStreamWriter.java:1502)
at com.ctc.wstx.sw.BaseStreamWriter.finishDocument(BaseStreamWriter.java:1663)
at com.ctc.wstx.sw.BaseStreamWriter.close(BaseStreamWriter.java:288)
at MyDataConverter.marshal(MyDataConverter.java:53)

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

Модификация package-info.java ссылка

Самое простое решение, которое я нашел. Обычно это работает, но этот файл создается при каждой сборке. Вот почему я должен найти другое решение.

Модификация схемы ссылка

Работает как описано, но не решает мою проблему. У меня все еще есть пространство имен в корневом элементе.

DelegatingXMLStreamWriter ссылка

Я также пробовал решения, упомянутые там, но у меня было странное утверждение в com.sun.xml.bind.v2.runtime.output.NamespaceContextImpl (метод DeclareNsUri), который я не смог победить.

Мое решение

При изучении проблемы с утверждением мне пришлось реализовать собственную версию XMLStreamWriter на основе DelegatingXMLStreamWriter.java

public class NamespaceStrippingXMLStreamWriter extends DelegatingXMLStreamWriter {

  public NamespaceStrippingXMLStreamWriter(XMLStreamWriter xmlWriter) throws XMLStreamException {
    super(xmlWriter);
  }

  @Override
  public void writeNamespace(String prefix, String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeDefaultNamespace(String uri) throws XMLStreamException {
    // intentionally doing nothing
  }

  @Override
  public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeStartElement(null, local, null);
  }

  @Override
  public void writeStartElement(String uri, String local) throws XMLStreamException {
    super.writeStartElement(null, local);
  }

  @Override
  public void writeEmptyElement(String uri, String local) throws XMLStreamException {
    super.writeEmptyElement(null, local);
  }

  @Override
  public void writeEmptyElement(String prefix, String local, String uri) throws XMLStreamException {
    super.writeEmptyElement(null, local, null);
  }

  @Override
  public void writeAttribute(String prefix, String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, null, local, value);
  }

  @Override
  public void writeAttribute(String uri, String local, String value) throws XMLStreamException {
    super.writeAttribute(null, local, value);
  }
}

Основная идея состоит в том, чтобы избежать передачи информации о пространстве имен в базовый XMLStreamWriter. Надеюсь, это поможет вам сэкономить время на решение аналогичной проблемы.

PS. Нет необходимости расширять DelegatingXMLStreamWriter в вашем коде. Я сделал это, чтобы показать, какие методы нужно изменить.

2 голосов
/ 29 апреля 2015

Для меня простой вызов xmlStreamWriter.setDefaultNamespace("") решил проблему.

Еще одна вещь, которую вы должны позаботиться, чтобы удалить префикс пространства имен из выходных данных, это то, что везде, где есть @XmlElement, убедитесь, что оно не включает свойство пространства имен, например @XmlElement(name="", namespace"http://..."); в противном случае ни одно из решений не будет работать.

0 голосов
/ 31 июля 2015

Это работает для меня:

marshaller.setProperty (Marshaller.JAXB_SCHEMA_LOCATION, "");

0 голосов
/ 12 мая 2010

Если вы не укажете пространство имен, JaxB не напишет его.

Yout может использовать Stax в потоке, если ваша задача не слишком сложна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...