JAXB将JAVA对象转换为XML时CDATA的问题

 

对Java对象转换为xml字符串时,如果有特殊字符如<>必须要是用<![CDATA[]]>来声明。我先尝试了使用XStream解决这个问题也有使用MOXy CDATA注解解决,最后发现,都存在一定的缺陷,甚至不能正常的实现该功能。

最终解决方案有两个,都可以解决这个问题,但是第一个方案由于引用了sun的专有API,在编译时会存在警告,使用了内部的API并不是值得推荐的。但是这里也贴出来,供大家参考。

sunAPI版:

首先继承XMLSerializer

 

[java] view plain copy
 
  1. import com.sun.org.apache.xml.internal.serialize.OutputFormat;  
  2. import com.sun.org.apache.xml.internal.serialize.XMLSerializer;  
  3. import org.xml.sax.SAXException;  
  4.   
  5. import java.io.OutputStream;  
  6. import java.util.regex.Pattern;  
  7.   
  8. public class CDataContentHandler extends XMLSerializer {  
  9.     private static final Pattern XML_CHARS = Pattern.compile("[<>&]");  
  10.   
  11.     public CDataContentHandler( OutputStream output, OutputFormat format ) {  
  12.        super(output,format);  
  13.     }  
  14.   
  15.     public void characters(char[] ch, int start, int length) throws SAXException {  
  16.         boolean useCData = XML_CHARS.matcher(new String(ch, start, length)).find();  
  17.         if (useCData) super.startCDATA();  
  18.         super.characters(ch, start, length);  
  19.         if (useCData) super.endCDATA();  
  20.     }  
  21.   
  22. }  

 

实际的转换方法:

 

[java] view plain copy
 
  1. public static String ojbectToXmlWithCDATA(Class clazz, Object obj) throws Exception {  
  2.   
  3.             JAXBContext context = JAXBContext.newInstance(clazz);  
  4.   
  5.             OutputFormat of = new OutputFormat();  
  6.             of.setOmitXMLDeclaration(true);  
  7.             of.setPreserveSpace(true);  
  8.             of.setIndenting(true);  
  9.   
  10.             ByteArrayOutputStream op = new ByteArrayOutputStream();  
  11.             CDataContentHandler serializer = new CDataContentHandler(op, of);  
  12.             SAXResult result = new SAXResult(serializer.asContentHandler());  
  13.   
  14.             Marshaller mar = context.createMarshaller();  
  15.             mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);  
  16.             mar.marshal(obj, result);  
  17.   
  18.             return op.toString("UTF-8");  
  19.         }  

第二个方法是目前使用的方法,参考了一个国外同行的解决方法,这个解决方案将自定实现javax.xml.stream.xmlstreamwriter,没有第三方的库依赖:

 

执行类决定哪些地方需要添加CDATA:

 

[java] view plain copy
 
  1. import javax.xml.stream.XMLStreamException;  
  2. import javax.xml.stream.XMLStreamWriter;  
  3. import java.util.regex.Pattern;  
  4.    
  5. /** 
  6.  * Implementation which is able to decide to use a CDATA section for a string. 
  7.  */  
  8. public class CDataXMLStreamWriter extends DelegatingXMLStreamWriter  
  9. {  
  10.    private static final Pattern XML_CHARS = Pattern.compile( "[&<>]" );  
  11.    
  12.    public CDataXMLStreamWriter( XMLStreamWriter del )  
  13.    {  
  14.       super( del );  
  15.    }  
  16.    
  17.    @Override  
  18.    public void writeCharacters( String text ) throws XMLStreamException  
  19.    {  
  20.       boolean useCData = XML_CHARS.matcher( text ).find();  
  21.       if( useCData )  
  22.       {  
  23.          super.writeCData( text );  
  24.       }  
  25.       else  
  26.       {  
  27.          super.writeCharacters( text );  
  28.       }  
  29.    }  
  30. }  

委托类:

 

 

[java] view plain copy
 
  1. import javax.xml.namespace.NamespaceContext;  
  2. import javax.xml.stream.XMLStreamException;  
  3. import javax.xml.stream.XMLStreamWriter;  
  4.    
  5. /** 
  6.  * Delegating {@link XMLStreamWriter}. 
  7.  */  
  8. abstract class DelegatingXMLStreamWriter implements XMLStreamWriter  
  9. {  
  10.    private final XMLStreamWriter writer;  
  11.    
  12.    public DelegatingXMLStreamWriter( XMLStreamWriter writer )  
  13.    {  
  14.       this.writer = writer;  
  15.    }  
  16.    
  17.    public void writeStartElement( String localName ) throws XMLStreamException  
  18.    {  
  19.       writer.writeStartElement( localName );  
  20.    }  
  21.    
  22.    public void writeStartElement( String namespaceURI, String localName ) throws XMLStreamException  
  23.    {  
  24.       writer.writeStartElement( namespaceURI, localName );  
  25.    }  
  26.    
  27.    public void writeStartElement( String prefix, String localName, String namespaceURI ) throws XMLStreamException  
  28.    {  
  29.       writer.writeStartElement( prefix, localName, namespaceURI );  
  30.    }  
  31.    
  32.    public void writeEmptyElement( String namespaceURI, String localName ) throws XMLStreamException  
  33.    {  
  34.       writer.writeEmptyElement( namespaceURI, localName );  
  35.    }  
  36.    
  37.    public void writeEmptyElement( String prefix, String localName, String namespaceURI ) throws XMLStreamException  
  38.    {  
  39.       writer.writeEmptyElement( prefix, localName, namespaceURI );  
  40.    }  
  41.    
  42.    public void writeEmptyElement( String localName ) throws XMLStreamException  
  43.    {  
  44.       writer.writeEmptyElement( localName );  
  45.    }  
  46.    
  47.    public void writeEndElement() throws XMLStreamException  
  48.    {  
  49.       writer.writeEndElement();  
  50.    }  
  51.    
  52.    public void writeEndDocument() throws XMLStreamException  
  53.    {  
  54.       writer.writeEndDocument();  
  55.    }  
  56.    
  57.    public void close() throws XMLStreamException  
  58.    {  
  59.       writer.close();  
  60.    }  
  61.    
  62.    public void flush() throws XMLStreamException  
  63.    {  
  64.       writer.flush();  
  65.    }  
  66.    
  67.    public void writeAttribute( String localName, String value ) throws XMLStreamException  
  68.    {  
  69.       writer.writeAttribute( localName, value );  
  70.    }  
  71.    
  72.    public void writeAttribute( String prefix, String namespaceURI, String localName, String value )  
  73.       throws XMLStreamException  
  74.    {  
  75.       writer.writeAttribute( prefix, namespaceURI, localName, value );  
  76.    }  
  77.    
  78.    public void writeAttribute( String namespaceURI, String localName, String value ) throws XMLStreamException  
  79.    {  
  80.       writer.writeAttribute( namespaceURI, localName, value );  
  81.    }  
  82.    
  83.    public void writeNamespace( String prefix, String namespaceURI ) throws XMLStreamException  
  84.    {  
  85.       writer.writeNamespace( prefix, namespaceURI );  
  86.    }  
  87.    
  88.    public void writeDefaultNamespace( String namespaceURI ) throws XMLStreamException  
  89.    {  
  90.       writer.writeDefaultNamespace( namespaceURI );  
  91.    }  
  92.    
  93.    public void writeComment( String data ) throws XMLStreamException  
  94.    {  
  95.       writer.writeComment( data );  
  96.    }  
  97.    
  98.    public void writeProcessingInstruction( String target ) throws XMLStreamException  
  99.    {  
  100.       writer.writeProcessingInstruction( target );  
  101.    }  
  102.    
  103.    public void writeProcessingInstruction( String target, String data ) throws XMLStreamException  
  104.    {  
  105.       writer.writeProcessingInstruction( target, data );  
  106.    }  
  107.    
  108.    public void writeCData( String data ) throws XMLStreamException  
  109.    {  
  110.       writer.writeCData( data );  
  111.    }  
  112.    
  113.    public void writeDTD( String dtd ) throws XMLStreamException  
  114.    {  
  115.       writer.writeDTD( dtd );  
  116.    }  
  117.    
  118.    public void writeEntityRef( String name ) throws XMLStreamException  
  119.    {  
  120.       writer.writeEntityRef( name );  
  121.    }  
  122.    
  123.    public void writeStartDocument() throws XMLStreamException  
  124.    {  
  125.       writer.writeStartDocument();  
  126.    }  
  127.    
  128.    public void writeStartDocument( String version ) throws XMLStreamException  
  129.    {  
  130.       writer.writeStartDocument( version );  
  131.    }  
  132.    
  133.    public void writeStartDocument( String encoding, String version ) throws XMLStreamException  
  134.    {  
  135.       writer.writeStartDocument( encoding, version );  
  136.    }  
  137.    
  138.    public void writeCharacters( String text ) throws XMLStreamException  
  139.    {  
  140.       writer.writeCharacters( text );  
  141.    }  
  142.    
  143.    public void writeCharacters( char[] text, int start, int len ) throws XMLStreamException  
  144.    {  
  145.       writer.writeCharacters( text, start, len );  
  146.    }  
  147.    
  148.    public String getPrefix( String uri ) throws XMLStreamException  
  149.    {  
  150.       return writer.getPrefix( uri );  
  151.    }  
  152.    
  153.    public void setPrefix( String prefix, String uri ) throws XMLStreamException  
  154.    {  
  155.       writer.setPrefix( prefix, uri );  
  156.    }  
  157.    
  158.    public void setDefaultNamespace( String uri ) throws XMLStreamException  
  159.    {  
  160.       writer.setDefaultNamespace( uri );  
  161.    }  
  162.    
  163.    public void setNamespaceContext( NamespaceContext context ) throws XMLStreamException  
  164.    {  
  165.       writer.setNamespaceContext( context );  
  166.    }  
  167.    
  168.    public NamespaceContext getNamespaceContext()  
  169.    {  
  170.       return writer.getNamespaceContext();  
  171.    }  
  172.    
  173.    public Object getProperty( String name ) throws IllegalArgumentException  
  174.    {  
  175.       return writer.getProperty( name );  
  176.    }  
  177. }  

示例方法:

 

 

[java] view plain copy
 
  1.     /**使用JAXB方式解决CDATA问题 
  2.      * 
  3.      * @throws Exception 
  4.      */  
  5.     public static String ojbectToXmlWithCDATA(Class clazz, Object obj) throws Exception {  
  6.   
  7.         JAXBContext context = JAXBContext.newInstance(clazz);  
  8.         ByteArrayOutputStream op = new ByteArrayOutputStream();  
  9.   
  10.         XMLOutputFactory xof = XMLOutputFactory.newInstance();  
  11.         XMLStreamWriter streamWriter = xof.createXMLStreamWriter(op);  
  12.         CDataXMLStreamWriter cdataStreamWriter = new CDataXMLStreamWriter(streamWriter);  
  13.   
  14.         Marshaller mar = context.createMarshaller();  
  15.         mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);  
  16.         mar.marshal(obj, cdataStreamWriter);  
  17.       cdataStreamWriter.flush();  
  18.       cdataStreamWriter.close();  
  19.         return op.toString("UTF-8");  
  20.     }  

 

生成后的xml代码示例:

 

[html] view plain copy
 
  1. <?xml version='1.0' encoding='utf-8'?>  
  2. <businessMessages xmlns="http://aaa.xxx.com/schema/BusinessMessages">  
  3.     <businessMessage>  
  4.         <uuid>abcccc</uuid>  
  5.         <source>tms</source>  
  6.         <topic>type</topic>  
  7.         <bussinessNo>123</bussinessNo>  
  8.         <header></header>  
  9.         <body>  
  10.             <![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>]]>  
  11. </body>  
  12.     </businessMessage>  
  13. </businessMessages>  


英文原文参考:http://blog.mi-ernst.de/2012/05/04/jaxb-and-cdata-sections/

 

博客来源:http://blog.csdn.net/wantken/article/details/50675549

 

posted @ 2018-01-22 19:43  yangchunlong  阅读(1332)  评论(1编辑  收藏  举报