web-dev-qa-db-ja.com

JAXBはXMLをOutputStreamとStringWriterとは異なる方法でマーシャリングします

これが回答された場合はお詫びしますが、使用している検索用語(つまり、JAXB @XmlAttribute Condensedまたは- JAXB XMLマーシャルから文字列への異なる結果)は何も思いつきません。

JAXBを使用して、_@XmlElement_および_@XmlAttribute_アノテーションが付けられたオブジェクトをアン/マーシャリングしています。 2つのメソッドを提供するフォーマッタークラスがあります。1つはマーシャルメソッドをラップしてオブジェクトをマーシャルとOutputStreamに受け入れ、もう1つはオブジェクトを受け入れてXML出力を文字列として返します。残念ながら、これらのメソッドは同じオブジェクトに対して同じ出力を提供しません。ファイルにマーシャリングする場合、内部で_@XmlAttribute_でマークされた単純なオブジェクトフィールドは次のように出力されます。

_<element value="VALUE"></element>
_

文字列にマーシャリングする場合、次のようになります。

_<element value="VALUE"/>
_

どちらの場合も2番目の形式を使用したいのですが、違いを制御する方法に興味があり、どちらの場合も同じであることに同意します。両方のメソッドが異なるインスタンス値を削除するために使用する静的マーシャラーを1つ作成しました。フォーマットコードは次のとおりです。

_/** Marker interface for classes which are listed in jaxb.index */
public interface Marshalable {}
_

_/** Local exception class */
public class XMLMarshalException extends BaseException {}
_

_/** Class which un/marshals objects to XML */
public class XmlFormatter {
    private static Marshaller marshaller = null;
    private static Unmarshaller unmarshaller = null;

    static {
        try {
            JAXBContext context = JAXBContext.newInstance("path.to.package");
            marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

            unmarshaller = context.createUnmarshaller();
        } catch (JAXBException e) {
            throw new RuntimeException("There was a problem creating a JAXBContext object for formatting the object to XML.");
        }
    }

    public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
        try {
            marshaller.marshal(obj, os);
        } catch (JAXBException jaxbe) {
            throw new XMLMarshalException(jaxbe);
        }
    }

    public String marshalToString(Marshalable obj) throws XMLMarshalException {
        try {
            StringWriter sw = new StringWriter();
            return marshaller.marshal(obj, sw);
        } catch (JAXBException jaxbe) {
            throw new XMLMarshalException(jaxbe);
        }
    }
}
_

_/** Example data */
@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class Data {

    @XmlAttribute(name = value)
    private String internalString;
}
_

_/** Example POJO */
@XmlType
@XmlRootElement(namespace = "project/schema")
@XmlAccessorType(XmlAccessType.FIELD)
public class Container implements Marshalable {

    @XmlElement(required = false, nillable = true)
    private int number;

    @XmlElement(required = false, nillable = true)
    private String Word;

    @XmlElement(required = false, nillable = true)
    private Data data;
}
_

marshal(container, new FileOutputStream("output.xml"))およびmarshalToString(container)を呼び出した結果は次のとおりです。

ファイルへの出力

_<?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<ns2:container xmlns:ns2="project/schema">  
    <number>1</number>  
    <Word>stackoverflow</Word>  
    <data value="This is internal"></data>  
</ns2:container>
_

そして

文字列への出力

_<?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<ns2:container xmlns:ns2="project/schema">  
    <number>1</number>  
    <Word>stackoverflow</Word>  
    <data value="This is internal"/>  
</ns2:container>
_
12
Andy

これはJAXBの「バグ」のようです。ソースを見ると、marshal()の呼び出しは、出力/ライタータイプパラメーターに基づいて異なるライターを作成します。

public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException {
    write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer));
}

public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException {
    write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer));
}

ライターの実装は、「空の要素」を処理する方法に関して異なります。上記のコードは次のものです。

jaxb-ri\runtime\src\com\Sun\xml\bind\v2\runtime\MarshallerImpl.Java。

作成している2人のライターは次のとおりです。

jaxb-ri\runtime\src\com\Sun\xml\bind\v2\runtime\output\UTF8XmlOutput.Java

jaxb-ri\runtime\src\com\Sun\xml\bind\v2\runtime\output\XMLStreamWriterOutput.Java

8

幸いなことに、JAXBは(JPAのように)複数の実装を持つ仕様です。 1つの実装がニーズを満たしていない場合は、EclipseLink JAXB(MOXy)などの他の実装を利用できます。

2
bdoughan

JAXBがなぜこれを行っているのか(またはJAXBであっても)、たとえばJAXBがSAXContentHandlerを介してXMLを出力している場合、タグの生成方法を直接制御することはできません。

一貫した動作を得るには、OutputStreamをOutputStreamWriterでラップすることができます。

   public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException {
        try {
            marshaller.marshal(obj, new OutputStreamWriter(os, "UTF-8"));
        } catch (JAXBException jaxbe) {
            throw new XMLMarshalException(jaxbe);
        }
    }

同じ行に沿って、StringWriterをPrintWriterでラップするとどうなるかがわかるかもしれません。おそらく、出力をできるだけ短くしようとするStringWriterを検出するカスタムコードがいくつかあります。ありそうもないように聞こえますが、他に説明はありません。

1
mdma

なぜそれが重要なのですか? <tag attribute = "value"> </ tag>は、xmlの<tag attribute = "value" />と同等です。

0
Lily Chung