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チャンクをチャンクごとにシリアル化するより良い方法はありますか?
次は私のためのトリックをしました:
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注釈付きクラスがあるパッケージ内)。そこには@XmlSchema
のnamespace
属性があります。
また、@XmlRootElement
アノテーションにはnamespace
属性があります。
あなたのケースで名前空間プレフィックスを取り除く非常に簡単な方法があります:次のように、スキーマで属性elementFormDefaultをnqualifiedに設定するだけです:
<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
ここで回答として提供されたすべてのソリューションを試してみましたが、どれも私の環境では機能しませんでした。私の現在の要件は次のとおりです。
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を拡張する必要はありません。これは、どのメソッドを変更する必要があるかを示すために行いました。
私にとって、xmlStreamWriter.setDefaultNamespace("")
を呼び出すだけで問題は解決しました。
出力から名前空間プレフィックスを削除するために注意する必要があるもう1つのことは、@ XmlElementがあるすべての場所に、@XmlElement(name="", namespace"http://...")
などの名前空間プロパティが含まれていないことを確認することです。そうでなければ、解決策はどれも機能しません。
名前空間を指定しない場合、JaxBは名前空間を書き込みません。
構造が複雑でなければ、ストリームでStaxを使用することはできません。