【问题标题】:How to marshal without a namespace?如何在没有命名空间的情况下编组?
【发布时间】:2011-02-18 11:01:45
【问题描述】:

我有一个相当大的重复 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,但它看起来很丑,所以我想知道有没有办法告诉编组器不要为项目元素放置命名空间?或者有没有更好的方法来使用 JAXB 逐块序列化为 XML 块?

【问题讨论】:

  • 实际上你的实现和建议的输出不匹配。你自己写根标签,为什么根元素上的输出中有一个命名空间。
  • 啊,很好的收获。因为我实际上也使用 JAXB 来“硬编码”根元素。所以我所做的是创建一个空的 Root 对象,将其编组为字符串,然后解析字符串以提取根标签。所以如果 JAXB 没有为根标签生成命名空间,那我就完蛋了。

标签: java xml jaxb


【解决方案1】:

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

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

【讨论】:

  • 但事实上我需要一个命名空间,但只是在根元素级别。
【解决方案2】:

检查您的package-info.java(在您的 jaxb 注释类所在的包中)。那里有@XmlSchemanamespace 属性。

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

【讨论】:

  • 有没有办法在绑定文件中指定不在我的 package-info.java 中放入命名空间,而只在 @XmlRootElement 中放入命名空间?
  • 您可以在@XmlRootElement 中覆盖它,但据我了解,您希望将其完全删除。
  • 我尝试添加 -npa 但由于某种原因它在 jaxb2-maven-plugin 上不起作用。我只想在自动生成的 package-info.java 中将命名空间属性设为“” .我的@XmlRootElement 具有命名空间=“”,但是当它被编组时,它仍然获得了package-info.java 中存在的命名空间。在此处完成详细信息:stackoverflow.com/questions/15796063/…
【解决方案3】:

以下内容对我有用:

         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;
            }
        });

【讨论】:

【解决方案4】:

在您的情况下,有一种非常简单的方法可以消除命名空间前缀:只需在您的架构中将属性 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">

我希望这会有所帮助。

问候 帕维尔·普罗卡伊

【讨论】:

  • 这很好用,但是有没有办法摆脱第一个(根)标签中的命名空间?
【解决方案5】:

对我来说,只需致电xmlStreamWriter.setDefaultNamespace("") 即可解决问题。

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

【讨论】:

    【解决方案6】:

    这对我有用:

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

    【讨论】:

      【解决方案7】:

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

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

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

      自定义命名空间上下文 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的修改 link

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

      架构修改 link

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

      委托XMLStreamWriter link

      我也尝试过那里提到的解决方案,但我在 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。我这样做是为了说明哪些方法需要更改。

      【讨论】:

        猜你喜欢
        • 2011-11-03
        • 2014-10-09
        • 1970-01-01
        • 2023-01-25
        • 2019-02-22
        • 1970-01-01
        • 2020-04-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多