XStream添加 CDATA标签解析

了解CDATA

在XML元素中,”<”和”&”是非法的,如果使用这些特殊字符,那么解析器在解析文档时会产生错误。为了避免此类错误,需要把”<”这类特殊字符替换为实体引用,如

<user>age &lt; 25</user> //<user>age < 25</user>

 

在 XML 中有 5 个预定义的实体引用:

实体引用符号说明
&lt;<小于
&gt;>大于
&amp;&和号
&apos;省略号
&quot;引号

注释:严格地讲,在 XML 中仅有字符 “<”和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。

而 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data),CDATA 部分中的所有内容都会被解析器忽略,CDATA 部分由 <![CDATA[ 开始,由 ]]> 结束。所以,我们可以使用 CDATA 标签帮我们忽略某些特殊字符。

XStream是一个Java对象与XML互相转换的工具类库。

首先,先说说实现原理吧,由于对象不是所有字段都增加 CDATA 标签,我们可以使用自定义注解方式,在需要添加 CDATA 标签的字段加上注解,然后改写XPPDriver,通过反射查找添加注解的field,在输出XML文本时加上<![CDATA[]]>。废话不多说……

实现

一、创建注解

创建自定义注解@XStreamCDATA

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface XStreamCDATA {
    
}

二、创建XStreamFactory,改写XPPDriver

public class XStreamFactory {
    public static final String CDATA_PREFIX = "<![CDATA[";
    public static final String CDATA_SUFFIX = "]]>";
    public static XStream getXStream() {
        final NameCoder nameCoder = new NoNameCoder();
        XStream xStream = new XStream(new XppDomDriver(nameCoder) {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out, nameCoder) {
                    boolean cdataFlag = false;
                    Class<?> targetClass = null;
                    @Override
                    public void startNode(String name, Class clazz) {
                        super.startNode(name, clazz);
                        if (targetClass == null) {
                            targetClass = clazz;
                        }
                        cdataFlag = isCDATA(targetClass, name);
                    }
                    @Override
                    public void writeText(QuickWriter writer, String text) {
                        if (cdataFlag) {
                            writer.write(Constants.CDATA_PREFIX);
                            writer.write(text);
                            writer.write(Constants.CDATA_SUFFIX);
                        } else {
                            writer.write(text);
                        }
                    }
                };
            }
        });
        return xStream;
    }
    private static boolean isCDATA(Class<?> clazz, String fieldAlias) {
        //检查类本身
        boolean cdataFlag = isExistCDATA(clazz, fieldAlias);
        if (cdataFlag) {
            return cdataFlag;
        }
        //继续检查父类
        Class<?> superClazz = clazz.getSuperclass();
        while (!superClazz.equals(Object.class)) {
            cdataFlag = isExistCDATA(superClazz, fieldAlias);
            if (cdataFlag) {
                return cdataFlag;
            }
            superClazz = superClazz.getClass().getSuperclass();
        }
        return false;
    }
    /**
     * 检查是否有 @XStreamCDATA 注解
     * @param clazz clazz
     * @param fieldAlias fieldAlias
     * @return
     */
    private static boolean isExistCDATA(Class<?> clazz, String fieldAlias) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getAnnotation(XStreamCDATA.class) != null) {
                XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
                if (xStreamAlias != null && fieldAlias.equals(xStreamAlias.value())) {
                    return true;
                } else {
                    if (fieldAlias.equals(field.getName())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}

三、创建工具类

public class XmlUtils {
    private static final XStream xStream = XStreamFactory.getXStream();
    /**
     * 对象转xml
     * @param obj 对象
     * @return
     */
    public static String toXml(Object obj) {
        xStream.processAnnotations(obj.getClass());
        return xStream.toXML(obj);
    }
}

四、创建对象类

由于最近在做微信公众号开发,直接就拿一个类来做演示。字段添加@XStreamCDATA注解:

@XStreamAlias("xml")
public class WechatOutTextMsg implements Serializable {
    private static final long serialVersionUID = -1883441132514476532L;
    /**
     * 接收方账号(收到的OpenID)
     */
    @XStreamAlias("ToUserName")
    @XStreamCDATA
    private String toUserName;
    /**
     * 开发者微信号
     */
    @XStreamAlias("FromUserName")
    @XStreamCDATA
    private String fromUserName;
    /**
     * 消息创建时间(整形)
     */
    @XStreamAlias("CreateTime")
    private Long createTime;
    /**
     * 消息类型
     */
    @XStreamAlias("MsgType")
    @XStreamCDATA
    private String msgType;
    /**
     * 回复的消息内容
     */
    @XStreamAlias("Content")
    @XStreamCDATA
    private String content;
    
    //Getter and Setter...
}

五、测试

public class XmlUtilsTest {
    @Before
    public void before() throws Exception {
        
    }
    @After
    public void after() throws Exception {
    
    }
    /**
    *
    * Method: toXml(Object obj)
    *
    */
    @Test
    public void testToXml() throws Exception {
        WechatOutTextMsg outTextMsg = new WechatOutTextMsg();
        outTextMsg.setContent("你好");
        outTextMsg.setCreateTime((new Date()).getTime());
        outTextMsg.setFromUserName("fromUserName");
        outTextMsg.setMsgType("text");
        outTextMsg.setToUserName("toUserName");
        //转xml
        String str = XmlUtils.toXml(outTextMsg);
        System.out.println(str);
    }
}

结果输出

<xml>
  <ToUserName><![CDATA[toUserName]]></ToUserName>
  <FromUserName><![CDATA[fromUserName]]></FromUserName>
  <CreateTime>1511358600000</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[你好]]></Content>
</xml>

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值