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

Alv*_*vin 19 java xml jaxb

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

<Store>
  <item />
  <item />
  <item />
.....
</Store>
Run Code Online (Sandbox Code Playgroud)

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

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

foreach items as item
  aMarshaller.marshall(item, aOutputStream)
end
aOutputStream.write("</Store>")
aOutputStream.close()
Run Code Online (Sandbox Code Playgroud)

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

 <Store  xmlns="http://stackoverflow.com">
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
  <item xmlns="http://stackoverflow.com"/>
.....
</Store>
Run Code Online (Sandbox Code Playgroud)

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

Boz*_*zho 12

检查你的package-info.java(在你的jaxb注释类的包中).那里有namespace属性@XmlSchema.

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

  • 有没有办法在绑定文件中指定不将命名空间放在我的 package-info.java 中,而只将命名空间放在 @XmlRootElement 中? (2认同)

Tam*_*nai 9

以下为我做了诀窍:

         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;
            }
        });
Run Code Online (Sandbox Code Playgroud)


小智 7

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

<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:your="http://www.stackoverflow.com/your/namespace">
Run Code Online (Sandbox Code Playgroud)

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

<ns1:your xmlns:ns1="http://www.stackoverflow.com/your/namespace">
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助.

关心Pawel Procaj

  • 这很好用,但有没有办法摆脱第一个(根)标签中的命名空间? (7认同)

小智 7

我在这里尝试了所有解决方案作为答案,但没有一个适用于我的环境.我目前的要求是:

  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)
Run Code Online (Sandbox Code Playgroud)

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

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

主要思想是避免将名称空间信息传递给基础XMLStreamWriter.希望这能帮助您节省一些时间来解决类似的问题.

PS.没有必要在代码中扩展DelegatingXMLStreamWriter.我这样做是为了表明哪些方法需要改变.