问题描述
我在 Scala 中使用 JAXB,我的编组代码如下所示:
I'm using JAXB with Scala, my marshalling code looks like this:
def marshalToXml(): String = { val context = JAXBContext.newInstance(this.getClass()) val writer = new StringWriter context.createMarshaller.marshal(this, writer) writer.toString() }
然后对于我的可空元素,我使用注释 @XmlElement(nillable = true) 根据 带有空字段的 JAXB 编组.这给了我这样的 XML 输出:
Then for my nullable elements I'm using the annotation @XmlElement(nillable = true) as per JAXB Marshalling with null fields. This gives me XML output like so:
<name>Alex Dean</name> <customerReference xmlns:xsi="http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg" xsi:nil="true"/> <quantity>1</quantity> <createdAt>2011-05-14T00:00:00+03:00</createdAt>
这是一个好的开始,但我真正想为这些字段编组的是:
This is a good start but what I'd really like to marshal for these fields is:
<name>Alex Dean</name> <customerReference nil="true"/> <quantity type="integer">1</quantity> <createdAt type="datetime">2011-05-14T00:00:00+03:00</createdAt>
换句话说,我想删除命名空间属性和前缀,并为除字符串之外的所有内容添加显式 XML 数据类型属性.这可能很简单,但我似乎无法在 JAXB 文档中找到方法.
In other words, I would like to remove the namespace attributes and prefixes, and add in explicit XML datatype attributes for all but strings. It's probably quite simple to do but I can't seem to find how in the JAXB documentation.
感谢您的帮助!
推荐答案
您可以将 JAXB 与 StAX 解析器一起使用并执行以下操作:
You could use JAXB with a StAX parser and do the following:
客户
域模型中的每个属性都将使用 @XmlElement(nillable=true, type=Object.class) 进行映射.设置 type=Object.class 将强制写出 xsi:type 属性.
Each property in your domain model will be mapped with @XmlElement(nillable=true, type=Object.class). Setting the type=Object.class will force an xsi:type attribute to be written out.
package forum8198945; import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement public class Customer { private String name; private Customer customerReference; private Integer quantity; private Date createdAt; @XmlElement(nillable=true, type=Object.class) public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement(nillable=true, type=Object.class) public Customer getCustomerReference() { return customerReference; } public void setCustomerReference(Customer customerReference) { this.customerReference = customerReference; } @XmlElement(nillable=true, type=Object.class) public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } @XmlElement(nillable=true, type=Object.class) public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } }
XMLStreamWriterWrapper
我们将为 XMLStreamWriter 编写一个创建包装器,以剥离所有我们不想写入 XML 的信息.
We will write a create a wrapper for an XMLStreamWriter that strips off all the information we do not want written to XML.
package forum8198945; import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; public class XMLStreamWriterWrapper implements XMLStreamWriter { private XMLStreamWriter xmlStreamWriter; public XMLStreamWriterWrapper(XMLStreamWriter xmlStreamWriter) { this.xmlStreamWriter = xmlStreamWriter; } public void writeStartElement(String localName) throws XMLStreamException { xmlStreamWriter.writeStartElement(localName); } public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { xmlStreamWriter.writeStartElement(namespaceURI, localName); } public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { xmlStreamWriter.writeStartElement(prefix, localName, namespaceURI); } public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { xmlStreamWriter.writeEmptyElement(namespaceURI, localName); } public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { xmlStreamWriter.writeEmptyElement(prefix, localName, namespaceURI); } public void writeEmptyElement(String localName) throws XMLStreamException { xmlStreamWriter.writeEmptyElement(localName); } public void writeEndElement() throws XMLStreamException { xmlStreamWriter.writeEndElement(); } public void writeEndDocument() throws XMLStreamException { xmlStreamWriter.writeEndDocument(); } public void close() throws XMLStreamException { xmlStreamWriter.close(); } public void flush() throws XMLStreamException { xmlStreamWriter.flush(); } public void writeAttribute(String localName, String value) throws XMLStreamException { xmlStreamWriter.writeAttribute(localName, value); } public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException { if("http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg".equals(namespaceURI)) { int colonIndex = value.indexOf(':'); if(colonIndex > -1) { value = value.substring(colonIndex + 1); } xmlStreamWriter.writeAttribute(localName, value); } else { xmlStreamWriter.writeAttribute(prefix, namespaceURI, localName, value); } } public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { if("http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg".equals(namespaceURI)) { int colonIndex = value.indexOf(':'); if(colonIndex > -1) { value = value.substring(colonIndex + 1); } xmlStreamWriter.writeAttribute(localName, value); } else { xmlStreamWriter.writeAttribute(namespaceURI, localName, value); } } public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { if(!"http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg".equals(namespaceURI) && !"http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946694.jpg".equals(namespaceURI)) { xmlStreamWriter.writeNamespace(prefix, namespaceURI); } } public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { if(!"http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg".equals(namespaceURI)) { xmlStreamWriter.writeDefaultNamespace(namespaceURI); } } public void writeComment(String data) throws XMLStreamException { // TODO Auto-generated method stub } public void writeProcessingInstruction(String target) throws XMLStreamException { // TODO Auto-generated method stub } public void writeProcessingInstruction(String target, String data) throws XMLStreamException { // TODO Auto-generated method stub } public void writeCData(String data) throws XMLStreamException { // TODO Auto-generated method stub } public void writeDTD(String dtd) throws XMLStreamException { // TODO Auto-generated method stub } public void writeEntityRef(String name) throws XMLStreamException { // TODO Auto-generated method stub } public void writeStartDocument() throws XMLStreamException { xmlStreamWriter.writeStartDocument(); } public void writeStartDocument(String version) throws XMLStreamException { xmlStreamWriter.writeStartDocument(version); } public void writeStartDocument(String encoding, String version) throws XMLStreamException { xmlStreamWriter.writeStartDocument(encoding, version); } public void writeCharacters(String text) throws XMLStreamException { xmlStreamWriter.writeCharacters(text); } public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { xmlStreamWriter.writeCharacters(text, start, len); } public String getPrefix(String uri) throws XMLStreamException { return xmlStreamWriter.getPrefix(uri); } public void setPrefix(String prefix, String uri) throws XMLStreamException { xmlStreamWriter.setPrefix(prefix, uri); } public void setDefaultNamespace(String uri) throws XMLStreamException { xmlStreamWriter.setDefaultNamespace(uri); } public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { xmlStreamWriter.setNamespaceContext(context); } public NamespaceContext getNamespaceContext() { return xmlStreamWriter.getNamespaceContext(); } public Object getProperty(String name) throws IllegalArgumentException { return xmlStreamWriter.getProperty(name); } }
XMLStreamReaderWrapper
我们需要为 XMLStreamReader 创建一个包装器,它添加我们在 XMLStreamWriter 上剥离的所有内容.这对于 XMLStreamReader 来说更容易做到,因为我们可以扩展 StreamReaderDelegate.
We need to create a wrapper for XMLStreamReader that adds everything that we stripped off on the XMLStreamWriter. This is easier to do for XMLStreamReader since we can extend StreamReaderDelegate.
package forum8198945; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; public class XMLStreamReaderWrapper extends StreamReaderDelegate { public XMLStreamReaderWrapper(XMLStreamReader xmlStreamReader) { super(xmlStreamReader); } @Override public String getAttributeNamespace(int index) { String attributeName = getAttributeLocalName(index); if("type".equals(attributeName) || "nil".equals(attributeName)) { return "http://www.51sjk.com/Upload/Articles/1/0/337/337444_20221117112946212.jpg"; } return super.getAttributeNamespace(index); } }
演示
以下内容展示了所有内容是如何结合在一起的:
The following demonstrates how everything comes together:
package forum8198945; import java.io.StringReader; import java.io.StringWriter; import java.util.Date; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Customer customer = new Customer(); customer.setName("Alex Dean"); customer.setCustomerReference(null); customer.setQuantity(1); customer.setCreatedAt(new Date()); StringWriter stringWriter = new StringWriter(); XMLOutputFactory xof = XMLOutputFactory.newFactory(); XMLStreamWriter xsw = xof.createXMLStreamWriter(stringWriter); xsw = new XMLStreamWriterWrapper(xsw); Marshaller marshaller = jc.createMarshaller(); marshaller.marshal(customer, xsw); String xml = stringWriter.toString(); System.out.println(xml); XMLInputFactory xif = XMLInputFactory.newFactory(); xif.createXMLStreamReader(new StringReader(xml)); printValue(customer.getName()); printValue(customer.getCustomerReference()); printValue(customer.getQuantity()); printValue(customer.getCreatedAt()); } private static void printValue(Object value) { System.out.print(value); System.out.print(" "); if(null != value) { System.out.print(value.getClass()); } System.out.println(); } }
输出
<?xml version="1.0"?><customer><createdAt type="dateTime">2011-11-25T13:36:49.095</createdAt><customerReference nil="true"></customerReference><name type="string">Alex Dean</name><quantity type="int">1</quantity></customer> Alex Dean class java.lang.String null 1 class java.lang.Integer Fri Nov 25 13:36:49 EST 2011 class java.util.Date