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


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

最终解决方案有两个,都可以解决这个问题,但是第一个方案由于引用了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/

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


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值