JAXB将JAVA对象转换为XML时CDATA的问题
2016-02-16 16:43
941 查看
对Java对象转换为xml字符串时,如果有特殊字符如<>必须要是用<![CDATA[]]>来声明。我先尝试了使用XStream解决这个问题也有使用MOXy CDATA注解解决,最后发现,都存在一定的缺陷,甚至不能正常的实现该功能。
最终解决方案有两个,都可以解决这个问题,但是第一个方案由于引用了sun的专有API,在编译时会存在警告,使用了内部的API并不是值得推荐的。但是这里也贴出来,供大家参考。
sunAPI版:
首先继承XMLSerializer
实际的转换方法:
第二个方法是目前使用的方法,参考了一个国外同行的解决方法,这个解决方案将自定实现javax.xml.stream.xmlstreamwriter,没有第三方的库依赖:
执行类决定哪些地方需要添加CDATA:
委托类:
示例方法:
生成后的xml代码示例:
英文原文参考:http://blog.mi-ernst.de/2012/05/04/jaxb-and-cdata-sections/
最终解决方案有两个,都可以解决这个问题,但是第一个方案由于引用了sun的专有API,在编译时会存在警告,使用了内部的API并不是值得推荐的。但是这里也贴出来,供大家参考。
sunAPI版:
首先继承XMLSerializer
import com.sun.org.apache.xml.internal.serialize.OutputFormat; import com.sun.org.apache.xml.internal.serialize.XMLSerializer; import org.xml.sax.SAXException; import java.io.OutputStream; import java.util.regex.Pattern; public class CDataContentHandler extends XMLSerializer { private static final Pattern XML_CHARS = Pattern.compile("[<>&]"); public CDataContentHandler( OutputStream output, OutputFormat format ) { super(output,format); } public void characters(char[] ch, int start, int length) throws SAXException { boolean useCData = XML_CHARS.matcher(new String(ch, start, length)).find(); if (useCData) super.startCDATA(); super.characters(ch, start, length); if (useCData) super.endCDATA(); } }
实际的转换方法:
public static String ojbectToXmlWithCDATA(Class clazz, Object obj) throws Exception { JAXBContext context = JAXBContext.newInstance(clazz); OutputFormat of = new OutputFormat(); of.setOmitXMLDeclaration(true); of.setPreserveSpace(true); of.setIndenting(true); ByteArrayOutputStream op = new ByteArrayOutputStream(); CDataContentHandler serializer = new CDataContentHandler(op, of); SAXResult result = new SAXResult(serializer.asContentHandler()); Marshaller mar = context.createMarshaller(); mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); mar.marshal(obj, result); return op.toString("UTF-8"); }
第二个方法是目前使用的方法,参考了一个国外同行的解决方法,这个解决方案将自定实现javax.xml.stream.xmlstreamwriter,没有第三方的库依赖:
执行类决定哪些地方需要添加CDATA:
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import java.util.regex.Pattern; /** * Implementation which is able to decide to use a CDATA section for a string. */ public class CDataXMLStreamWriter extends DelegatingXMLStreamWriter { private static final Pattern XML_CHARS = Pattern.compile( "[&<>]" ); public CDataXMLStreamWriter( XMLStreamWriter del ) { super( del ); } @Override public void writeCharacters( String text ) throws XMLStreamException { boolean useCData = XML_CHARS.matcher( text ).find(); if( useCData ) { super.writeCData( text ); } else { super.writeCharacters( text ); } } }
委托类:
import javax.xml.namespace.NamespaceContext; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; /** * Delegating {@link XMLStreamWriter}. */ abstract class DelegatingXMLStreamWriter implements XMLStreamWriter { private final XMLStreamWriter writer; public DelegatingXMLStreamWriter( XMLStreamWriter writer ) { this.writer = writer; } public void writeStartElement( String localName ) throws XMLStreamException { writer.writeStartElement( localName ); } public void writeStartElement( String namespaceURI, String localName ) throws XMLStreamException { writer.writeStartElement( namespaceURI, localName ); } public void writeStartElement( String prefix, String localName, String namespaceURI ) throws XMLStreamException { writer.writeStartElement( prefix, localName, namespaceURI ); } public void writeEmptyElement( String namespaceURI, String localName ) throws XMLStreamException { writer.writeEmptyElement( namespaceURI, localName ); } public void writeEmptyElement( String prefix, String localName, String namespaceURI ) throws XMLStreamException { writer.writeEmptyElement( prefix, localName, namespaceURI ); } public void writeEmptyElement( String localName ) throws XMLStreamException { writer.writeEmptyElement( localName ); } public void writeEndElement() throws XMLStreamException { writer.writeEndElement(); } public void writeEndDocument() throws XMLStreamException { writer.writeEndDocument(); } public void close() throws XMLStreamException { writer.close(); } public void flush() throws XMLStreamException { writer.flush(); } public void writeAttribute( String localName, String value ) throws XMLStreamException { writer.writeAttribute( localName, value ); } public void writeAttribute( String prefix, String namespaceURI, String localName, String value ) throws XMLStreamException { writer.writeAttribute( prefix, namespaceURI, localName, value ); } public void writeAttribute( String namespaceURI, String localName, String value ) throws XMLStreamException { writer.writeAttribute( namespaceURI, localName, value ); } public void writeNamespace( String prefix, String namespaceURI ) throws XMLStreamException { writer.writeNamespace( prefix, namespaceURI ); } public void writeDefaultNamespace( String namespaceURI ) throws XMLStreamException { writer.writeDefaultNamespace( namespaceURI ); } public void writeComment( String data ) throws XMLStreamException { writer.writeComment( data ); } public void writeProcessingInstruction( String target ) throws XMLStreamException { writer.writeProcessingInstruction( target ); } public void writeProcessingInstruction( String target, String data ) throws XMLStreamException { writer.writeProcessingInstruction( target, data ); } public void writeCData( String data ) throws XMLStreamException { writer.writeCData( data ); } public void writeDTD( String dtd ) throws XMLStreamException { writer.writeDTD( dtd ); } public void writeEntityRef( String name ) throws XMLStreamException { writer.writeEntityRef( name ); } public void writeStartDocument() throws XMLStreamException { writer.writeStartDocument(); } public void writeStartDocument( String version ) throws XMLStreamException { writer.writeStartDocument( version ); } public void writeStartDocument( String encoding, String version ) throws XMLStreamException { writer.writeStartDocument( encoding, version ); } public void writeCharacters( String text ) throws XMLStreamException { writer.writeCharacters( text ); } public void writeCharacters( char[] text, int start, int len ) throws XMLStreamException { writer.writeCharacters( text, start, len ); } public String getPrefix( String uri ) throws XMLStreamException { return writer.getPrefix( uri ); } public void setPrefix( String prefix, String uri ) throws XMLStreamException { writer.setPrefix( prefix, uri ); } public void setDefaultNamespace( String uri ) throws XMLStreamException { writer.setDefaultNamespace( uri ); } public void setNamespaceContext( NamespaceContext context ) throws XMLStreamException { writer.setNamespaceContext( context ); } public NamespaceContext getNamespaceContext() { return writer.getNamespaceContext(); } public Object getProperty( String name ) throws IllegalArgumentException { return writer.getProperty( name ); } }
示例方法:
/**使用JAXB方式解决CDATA问题 * * @throws Exception */ public static String ojbectToXmlWithCDATA(Class clazz, Object obj) throws Exception { JAXBContext context = JAXBContext.newInstance(clazz); ByteArrayOutputStream op = new ByteArrayOutputStream(); XMLOutputFactory xof = XMLOutputFactory.newInstance(); XMLStreamWriter streamWriter = xof.createXMLStreamWriter(op); CDataXMLStreamWriter cdataStreamWriter = new CDataXMLStreamWriter(streamWriter); Marshaller mar = context.createMarshaller(); mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); mar.marshal(obj, cdataStreamWriter); cdataStreamWriter.flush(); cdataStreamWriter.close(); return op.toString("UTF-8"); }
生成后的xml代码示例:
<?xml version='1.0' encoding='utf-8'?> <businessMessages xmlns="http://aaa.xxx.com/schema/BusinessMessages"> <businessMessage> <uuid>abcccc</uuid> <source>tms</source> <topic>type</topic> <bussinessNo>123</bussinessNo> <header></header> <body> <![CDATA[<pivotFlow xmlns="http://aaa.xxx.com/schema/PivotFlow"><orderId>112345</orderId><operPersonId>testOper</operPersonId><operTime>2016-02-16T16:13:40.364+08:00</operTime><status>testType</status><appendix>{"shipper":"testShip","carrierPhone":"1860132223","carrier":"testCarr"}</appendix></pivotFlow>]]> </body> </businessMessage> </businessMessages>
英文原文参考:http://blog.mi-ernst.de/2012/05/04/jaxb-and-cdata-sections/
相关文章推荐
- eclipse tips
- spring 对象初始化
- java jdk environment variables
- spring 中配置bean的注入是<property>的name与与ref的id名需要一样吗??
- java中key值可以重复的map:IdentityHashMap
- java.net.SocketTimeoutException: failed to connect to /10.0..2.2 (port 8080) after 10000ms
- java 获取本机的公网、外网ip
- struts之拦截器
- java 实现WebService 以及不同的调用方式
- java synchronized详解
- Java-day8反射 设计模式 JDK新特性
- Java的多线程之执行器
- 深入源码-spring事件通知机制详解
- Struts2基本原理
- eclipse 中 *.properties 中 unicode 显示 中文(国际化),需要安装Properties Editor
- CommonsMultipartFile---用Spring实现文件上传
- springMVC +mybatis的配置
- Java-day07多线程
- Java-day06异常及IO流
- Spring学习