我正在使用标准的JAXB实现 这是我的带注释的类(是一组类的一部分)
@XmlType()
@XmlAccessorType(FIELD)
class MyClass {
@XmlValue
protected final String value = null;
@XmlAttribute
protected String attr;
...get/set for attr...
}
我正在使用
编写根对象JaxbContext ctx = JAXBContext.newInstance("path.to.package");
XMLStreamWriter writer = new IndentingXMLStreamWriter(file); //stax-utils writer
ctx.marshal(rootObject, writer);
结果为<my-class attr="attrValue"></my-class>
,但我需要空标记为<my-class attr="attrValue"/>
。
我尝试了编写器和目标流的一些不同组合(并读取了十几个SO问题)(不仅是文件,还有StringWriter和其他人,但我需要将对象保存到文件中)。
有什么建议或解决方案吗?
答案 0 :(得分:2)
这是在编组到XMLStreamWriter
时可能出现的问题。如果您可以封送到File
,FileOutputStream
或FileWriter
来获取您正在寻找的行为。
注意:强>
要使用这些输出目标格式化输出,您可以在Marshaller
上设置以下属性:
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
答案 1 :(得分:1)
我决定使用自定义XMLStreamWriter,如果tag-name根本没有内容,则将<tag-name></tag-name>
替换为<tag-name/>
。
背后的想法是推迟 startElement-endElement 之间的写事件。
当找到 endElement 时,如果不是边界之间的内容事件,则使用 emptyElement 替换 startElement 并禁止 endElement 一点都不
对不起评论不好,我稍后会回来让它更容易理解。
public class EmptyTagXMLStreamWriter extends StreamWriterDelegate {
class Event {
Method m;
Object[] args;
}
enum EventEnum {
writeStartElement,
writeAttribute,
writeNamespace,
writeEndElement,
setPrefix,
setDefaultNamespace,
}
private List<Event> queue = new ArrayList<Event>();
protected EmptyTagXMLStreamWriter(XMLStreamWriter out) {
super(out);
}
@Override
public void writeStartElement(String localName) throws XMLStreamException {
d(e(m("writeStartElement",String.class)), localName);
}
@Override
public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException
{
d(e(m("writeStartElement",String.class,String.class)), namespaceURI, localName);
}
@Override
public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException
{
d(e(m("writeStartElement",String.class,String.class,String.class)), prefix, localName, namespaceURI);
}
@Override
public void writeAttribute(String localName, String value)
throws XMLStreamException {
d(e(m("writeAttribute",String.class, String.class)), localName, value);
}
@Override
public void writeAttribute(String namespaceURI, String localName,
String value) throws XMLStreamException {
d(e(m("writeAttribute",String.class, String.class, String.class)), namespaceURI, localName, value);
}
@Override
public void writeAttribute(String prefix, String namespaceURI,
String localName, String value) throws XMLStreamException {
d(e(m("writeAttribute",String.class, String.class, String.class, String.class)), prefix, namespaceURI, localName, value);
}
@Override
public void writeCData(String data) throws XMLStreamException {
fq();
super.writeCData(data);
}
@Override
public void writeCharacters(char[] text, int start, int len)
throws XMLStreamException {
fq();
super.writeCharacters(text, start, len);
}
@Override
public void writeCharacters(String text) throws XMLStreamException {
fq();
super.writeCharacters(text);
}
@Override
public void writeComment(String data) throws XMLStreamException {
fq();
super.writeComment(data);
}
@Override
public void writeDTD(String dtd) throws XMLStreamException {
fq();
super.writeDTD(dtd);
}
@Override
public void writeProcessingInstruction(String target)
throws XMLStreamException {
fq();
super.writeProcessingInstruction(target);
}
@Override
public void writeProcessingInstruction(String target, String data)
throws XMLStreamException {
fq();
super.writeProcessingInstruction(target, data);
}
@Override
public void writeNamespace(String prefix, String namespaceURI)
throws XMLStreamException {
d(e(m("writeNamespace",String.class, String.class)), prefix, namespaceURI);
}
@Override
public void writeEndElement() throws XMLStreamException {
d(e(m("writeEndElement")));
}
@Override
public void writeEndDocument() throws XMLStreamException {
fq();
super.writeEndDocument();
}
@Override
public void writeDefaultNamespace(String namespaceURI)
throws XMLStreamException {
super.writeDefaultNamespace(namespaceURI);
}
@Override
public void flush() throws XMLStreamException {
if(queue.isEmpty())
super.flush();
}
@Override
public void close() throws XMLStreamException {
fq();
out.close();
}
@Override
public void setPrefix(String prefix, String uri) throws XMLStreamException {
d(e(m("setPrefix", String.class, String.class)), prefix, uri);
}
@Override
public void setDefaultNamespace(String uri) throws XMLStreamException {
d(e(m("setDefaultNamespace", String.class)), uri);
}
void d(Event e,Object...args) throws XMLStreamException {
e.args = args;
switch(EventEnum.valueOf(e.m.getName()))
{
case writeStartElement:
fq();
queue.add(e);
break;
case writeAttribute:
case writeNamespace:
case setPrefix:
case setDefaultNamespace:
if(!queue.isEmpty())
queue.add(e);
else
ex(e, args);
break;
case writeEndElement:
if(!queue.isEmpty())
{
final Event e1 = queue.get(0);
e1.m = m("writeEmptyElement", e1.m.getParameterTypes());
fq();
}
else
{
ex(e, args);
}
break;
}
}
Event e(Method m,Object...params)
{
final Event e = new Event();
e.m = m;
e.args = params;
return e;
}
Method m(String methodName,Class<?>...args) throws XMLStreamException {
try {
return XMLStreamWriter.class.getMethod(methodName, args);
} catch (Exception e) {
throw new XMLStreamException(e);
}
}
void fq() throws XMLStreamException
{
for(int i = 0;i < queue.size();i++)
{
Event e = queue.get(i);
ex(e, e.args);
}
queue.clear();
}
void ex(Event e,Object...args) throws XMLStreamException
{
try
{
e.m.invoke(super.out, e.args);
}
catch(Exception ex)
{
throw new XMLStreamException(ex);
}
}
}