Java JAXB 以不同的方式封送 XML 到 OutputStream 和 StringWriter
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3023676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JAXB marshals XML differently to OutputStream vs. StringWriter
提问by Andy
I apologize if this has been answered, but the search terms I have been using (i.e. JAXB @XmlAttribute condensedor JAXB XML marshal to String different results) aren't coming up with anything.
如果有人回答了这个问题,我深表歉意,但我一直在使用的搜索词(即JAXB @XmlAttribute condensed或JAXB XML marshal to String different results)没有提出任何内容。
I am using JAXB to un/marshal objects annotated with @XmlElement
and @XmlAttribute
annotations. I have a formatter class which provides two methods -- one wraps the marshal method and accepts the object to marshal and an OutputStream
, the other just accepts the object and returns the XML output as a String. Unfortunately, these methods do not provide the same output for the same objects. When marshaling to a file, simple object fields internally marked with @XmlAttribute
are printed as:
我正在使用 JAXB 来取消/封送用@XmlElement
和@XmlAttribute
注释注释的对象。我有一个格式化程序类,它提供了两种方法——一种包装 marshal 方法并接受要编组的对象和 an OutputStream
,另一种只接受对象并将 XML 输出作为字符串返回。不幸的是,这些方法不会为相同的对象提供相同的输出。当编组到文件时,内部标记为的简单对象字段@XmlAttribute
打印为:
<element value="VALUE"></element>
while when marshaling to a String, they are:
而在编组到字符串时,它们是:
<element value="VALUE"/>
I would prefer the second format for both cases, but I am curious as to how to control the difference, and would settle for them being the same regardless. I even created one static marshaller that both methods use to eliminate different instance values. The formatting code follows:
对于这两种情况,我更喜欢第二种格式,但我很好奇如何控制差异,并且无论如何都会满足于它们是相同的。我什至创建了一个静态编组器,两种方法都使用它来消除不同的实例值。格式化代码如下:
/** 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;
}
The result of calling marshal(container, new FileOutputStream("output.xml"))
and marshalToString(container)
are as follows:
调用marshal(container, new FileOutputStream("output.xml"))
和的结果marshalToString(container)
如下:
Output to file
输出到文件
<?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>
and
和
Output to String
输出到字符串
<?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>
采纳答案by Eric Thorbjornsen
Looks like this might be a "bug" in JAXB. Looking at the source, the calls for marshal() create different writers based on the output/writer type parameter:
看起来这可能是 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));
}
The implementations of the writers is different with regards to how they handle "empty elements". The above code is from:
编写器的实现在如何处理“空元素”方面有所不同。以上代码来自:
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\MarshallerImpl.java.
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\MarshallerImpl.java。
The two writers you are creating are:
您正在创建的两个作家是:
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\output\UTF8XmlOutput.java
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
jaxb-ri\runtime\src\com\sun\xml\bind\v2\runtime\output\XMLStreamWriterOutput.java
回答by mdma
I don't know why JAXB is doing this - or even if it is JAXB - if JAXB is outputting XML via a SAXContentHandler for example, then it has no direct control over how close tags are produced.
我不知道 JAXB 为什么要这样做 - 或者即使它是 JAXB - 例如,如果 JAXB 通过 SAXContentHandler 输出 XML,那么它无法直接控制关闭标记的生成方式。
To get consistent behaviour, you could wrap your OutputStream in a OutputStreamWriter, e.g.
为了获得一致的行为,您可以将您的 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);
}
}
Along the same lines, you might see what happens if you wrap the StringWriter in a PrintWriter. Maybe there is some custom code that detects StringWriter
to tries to keep the output short as possible. Sounds unlikely, but I have no other explanation.
同样,如果将 StringWriter 包装在 PrintWriter 中,您可能会看到会发生什么。也许有一些自定义代码会检测StringWriter
到尝试使输出尽可能短。听起来不太可能,但我没有其他解释。
回答by bdoughan
The good news is that JAXB is a specification with more than one implementation (just like JPA). If one implementation is not meeting your needs, others are available such as EclipseLink JAXB (MOXy):
好消息是 JAXB 是一种具有多个实现的规范(就像 JPA 一样)。如果一种实现不能满足您的需求,则可以使用其他实现,例如 EclipseLink JAXB (MOXy):