web-dev-qa-db-ja.com

名前空間なしでマーシャリングする方法は?

JAXBを使用して作成するかなり大きな繰り返しXMLがあります。オブジェクト全体をメモリに格納してからマーシャリングを実行すると、メモリが大量に消費されます。基本的に、私のXMLは次のようになります。

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

現在の私の問題の解決策は、ルートタグを出力ストリームに「ハードコーディング」し、繰り返し要素を1つずつマーシャリングすることです。

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チャンクをチャンクごとにシリアル化するより良い方法はありますか?

19
Alvin

次は私のためのトリックをしました:

         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;
            }
        });
8
Tamas Kornai

package-info.Javaを確認します(jaxb注釈付きクラスがあるパッケージ内)。そこには@XmlSchemanamespace属性があります。

また、@XmlRootElementアノテーションにはnamespace属性があります。

12
Bozho

あなたのケースで名前空間プレフィックスを取り除く非常に簡単な方法があります:次のように、スキーマで属性elementFormDefaultnqualifiedに設定するだけです:

<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">

これがお役に立てば幸いです。

よろしくPawel Procaj

7
MrShinobi

ここで回答として提供されたすべてのソリューションを試してみましたが、どれも私の環境では機能しませんでした。私の現在の要件は次のとおりです。

  1. jdk1.6.0_45
  2. JAXB注釈付きクラスは、再構築のたびに生成されるため、それらを変更することはできません。

Stackoverflowで見つけたソリューションを使った実験の結果を皆さんと共有したいと思います。

Custom NamespaceContextlink

シンプルでエレガントなソリューションですが、私の環境では、次のスタックトレースの例外があります。

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

説明どおりに機能しますが、私の問題は解決しません。ルート要素に名前空間がまだあります。

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を拡張する必要はありません。これは、どのメソッドを変更する必要があるかを示すために行いました。

6
sergio

私にとって、xmlStreamWriter.setDefaultNamespace("")を呼び出すだけで問題は解決しました。

出力から名前空間プレフィックスを削除するために注意する必要があるもう1つのことは、@ XmlElementがあるすべての場所に、@XmlElement(name="", namespace"http://...")などの名前空間プロパティが含まれていないことを確認することです。そうでなければ、解決策はどれも機能しません。

2
HamedKhan

名前空間を指定しない場合、JaxBは名前空間を書き込みません。

構造が複雑でなければ、ストリームでStaxを使用することはできません。

0
tkr