Как сделать маршал без пространства имен?
У меня есть довольно большой повторяющийся 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://stackru.com">
<item xmlns="http://stackru.com"/>
<item xmlns="http://stackru.com"/>
<item xmlns="http://stackru.com"/>
.....
</Store>
Хотя это допустимый XML, но выглядит он просто ужасно, поэтому мне интересно, есть ли способ сказать маршаллеру не помещать пространство имен для элементов item? Или есть лучший способ использовать JAXB для сериализации в чанк XML?
7 ответов
Следующее помогло мне:
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;
}
});
Проверьте свои package-info.java
(в пакете, где находятся ваши jaxb-аннотированные классы). Здесь namespace
атрибут @XmlSchema
там.
Также есть namespace
атрибут в @XmlRootElement
аннотаций.
Я испробовал все решения, представленные в качестве ответов, и ни одно из них не помогло моей среде. Мои текущие требования:
- jdk1.6.0_45
- Аннотированные классы JAXB генерируются при каждой перестройке, поэтому изменение их не является вариантом.
Я хотел бы поделиться с вами результатами моих экспериментов с решениями, которые я нашел в stackru.
Custom NamespaceContext link
Простое и элегантное решение, но в моей среде у меня есть исключение со следующей трассировкой стека:
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
Самое простое решение, которое я нашел. Обычно это работает, но этот файл создается при каждой сборке. Вот почему я должен найти другое решение.
Ссылка на изменение схемы
Работает, как описано, но не решает мою проблему. У меня все еще есть пространство имен в корневом элементе.
Делегирование XMLStreamWriter ссылка
Я также пробовал решения, упомянутые там, но у меня было странное утверждение в 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 в вашем коде. Я сделал это, чтобы показать, какие методы нужно изменить.
В вашем случае есть очень простой способ избавиться от префиксов пространства имен: просто установите для атрибута elementFormDefault значение unqualified в вашей схеме, например:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:your="http://www.stackru.com/your/namespace">
Вы получите префикс пространства имен только в первом теге:
<ns1:your xmlns:ns1="http://www.stackru.com/your/namespace">
Надеюсь, это поможет.
С уважением Павел Процай
Для меня просто звонить xmlStreamWriter.setDefaultNamespace("")
решил проблему.
Еще одна вещь, которую вы должны позаботиться, чтобы удалить префикс пространства имен из выходных данных, это то, что везде, где у вас есть @XmlElement, убедитесь, что оно не включает свойство пространства имен, например @XmlElement(name="", namespace"http://...")
; в противном случае ни одно из решений не будет работать.
Если вы не укажете пространство имен, JaxB не напишет его.
Yout может использовать Stax в потоке, если ваша задача не слишком сложна.
Это работает для меня:
marshaller.setProperty (Marshaller.JAXB_SCHEMA_LOCATION, "");