如何在没有命名空间的情况下编组?

我有一个相当大的重复XML来使用JAXB创建。 将整个对象存储在内存中然后进行编组会占用太多内存。 基本上,我的XML看起来像这样:

    .....  

目前我对该问题的解决方案是将根标签“硬编码”到输出流,并逐个编组每个重复元素:

 aOutputStream.write("") aOutputStream.write("") foreach items as item aMarshaller.marshall(item, aOutputStream) end aOutputStream.write("") aOutputStream.close() 

不知何故,JAXB生成这样的XML

      .....  

虽然这是一个有效的XML,但它看起来很难看,所以我想知道有没有办法告诉编组人员不要为项目元素添加命名空间? 或者是否有更好的方法使用JAXB通过块序列化到XML块?

以下为我做了诀窍:

  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注释类的包中)。 那里有@XmlSchemanamespace属性。

此外, @XmlRootElement注释中还有一个namespace属性。

在您的情况下,有一种非常简单的方法可以摆脱名称空间前缀:只需在模式中将属性elementFormDefault设置为不合格 ,如下所示:

  

您将仅在第一个标记中获取名称空间前缀:

  

我希望这有帮助。

关心Pawel Procaj

我已经尝试了所有提供的解决方案作为答案,但没有一个适用于我的环境。 我目前的要求是:

  1. jdk1.6.0_45
  2. 每次重建时都会生成JAXB注释类,因此不能更改它们。

我想与您分享我在stackoverflow上找到的解决方案的实验结果。

自定义NamespaceContext 链接

简单而优雅的解决方案,但在我的环境中,我有以下堆栈跟踪的exception:

 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) 

我陷入困境,试图弄清楚为什么会发生这种exception并决定尝试别的东西。

package-info.java 链接的 修改

我找到的最简单的解决方案。 它通常可以工作,但是这个文件是在每次构建时生成的。 这就是我必须找到另一种解决方案的原因。

架构修改 链接

按照描述工作但不解决我的问题。 我仍然在根元素中有一个名称空间。

DelegatingXMLStreamWriter 链接

我也尝试过那里提到的解决方案,但是我在com.sun.xml.bind.v2.runtime.output.NamespaceContextImpl(方法declareNsUri)中有一个奇怪的断言,我没能打败它。

我的解决方案

在使用断言研究问题时,我必须基于DelegatingXMLStreamWriter.java实现我自己的XMLStreamWriter版本

 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。 我这样做是为了表明哪些方法需要改变。

对我来说,只需调用xmlStreamWriter.setDefaultNamespace("")解决问题。

为了从输出中删除命名空间前缀,你必须要注意的另一件事是,你拥有@XmlElement的任何地方都确保它不包含像@XmlElement(name="", namespace"http://...")这样的命名空间属性@XmlElement(name="", namespace"http://...") ; 否则,没有任何解决方案可行。

如果你没有指定命名空间,JaxB就不会写一个。

如果你的结构不复杂,Yout可以在Stream上使用Stax。

这对我有用:

marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,“”);