XStream双下划线问题解决与CDATA标记同时的方案

来源:互联网 发布:2017淘宝补单平台 编辑:程序博客网 时间:2024/05/17 06:13

1、问题

在微信开发过程中,需要进行xml格式的数据传输。有些微信接口的xml数据中需要加上CDATA标记,而大部分的xml数据的标签名都带有下划线。注意,微信接口中的数据是有下划线的,是“_”不是“-”,让我很郁闷。

2、使用XStream把Java对象转成xml格式的数据

            UnifiedOrder unifiedOrder = new UnifiedOrder();            unifiedOrder.setAppid("123456");            unifiedOrder.setAttach("hehedesk");            unifiedOrder.setBody("hehedesk");            unifiedOrder.setOpenid("5654675");            unifiedOrder.setSign("0000000000000000");            XStream stream = new XStream();            stream.alias("xml", unifiedOrder.getClass());            String xml = stream.toXML(unifiedOrder);            System.out.println(xml);

输出XML为:

<xml>  <appid>123456</appid>  <attach>hehedesk</attach>  <body>hehedesk</body>  <openid>5654675</openid>  <sign>0000000000000000</sign></xml>

3、为数据加上CDATA标记

修改XStream的实现就可以。

        XStream stream = new XStream(new XppDriver(new NoNameCoder()) {                @Override                public HierarchicalStreamWriter createWriter(Writer out) {                    return new PrettyPrintWriter(out) {                        // 对所有xml节点的转换都增加CDATA标记                        boolean cdata = true;                        @Override                        @SuppressWarnings("rawtypes")                        public void startNode(String name, Class clazz) {                            super.startNode(name, clazz);                        }                        @Override                        protected void writeText(QuickWriter writer, String text) {                            if (cdata) {                                writer.write("<![CDATA[");                                writer.write(text);                                writer.write("]]>");                            } else {                                writer.write(text);                            }                        }                    };                }            });

输出XML为:

<xml>  <appid><![CDATA[123456]]></appid>  <attach><![CDATA[hehedesk]]></attach>  <body><![CDATA[hehedesk]]></body>  <openid><![CDATA[5654675]]></openid>  <sign><![CDATA[0000000000000000]]></sign></xml>

4、当对象属性带下划线时,XStream转换成双下划线

            UnifiedOrder unifiedOrder = new UnifiedOrder();            unifiedOrder.setAppid("123456");            unifiedOrder.setAttach("hehedesk");            unifiedOrder.setBody("hehedesk");            unifiedOrder.setOpenid("5654675");            unifiedOrder.setSign("0000000000000000");            unifiedOrder.setMch_id("123456");            XStream stream = new XStream();            stream.alias("xml", unifiedOrder.getClass());            String xml = stream.toXML(unifiedOrder);

输出XML:

<xml>  <appid>123456</appid>  <mch__id>123456</mch__id>  <attach>hehedesk</attach>  <body>hehedesk</body>  <openid>5654675</openid>  <sign>0000000000000000</sign></xml>

注意:这里mch_id的下线线由XStream转成了”__”。

度娘上找到的解决方法:

new DomDriver(null,new XmlFriendlyNameCoder("_-", "_"))

经过测试,XmlFriendlyNameCoder与XppDriver不能同时存在。so,问题来了。如何才能让两者共存呢。

5、双下划线问题解决与CDATA标记同时的方案

双下划线问题的产生是因为XStream默认的转换方式中定义了对特殊字符的转换,代码如下:

//XmlFriendlyNameCoder.encodeName(String name)for (; i < length; i++ ) {            char c = name.charAt(i);            if (c == '$' || c == '_' || c <= 27 || c >= 127) {                break;            } }

也就是说,我们在转换的过程中,不对特殊字符进行转换就可以了。

XppDriver类中有对字符转换的方法:

    /**     * Encode the node name into the name of the target format.     *      * @param name the original name     * @return the name in the target format     * @since 1.4     */    public String encodeNode(String name) {        return nameCoder.encodeNode(name);    }

这里可以看到,XppDriver的encodeNode是把节点的名称进行格式化。然后调用nameCoder对象对名字进行编译。

我们在XppDriver的子类中,重写此方法,不再像XppDriver那样调用nameCoder来进行编译,而是直接返回节点名称。

@Overridepublic String encodeNode(String name) {    return name;}

完整代码如下:

            XStream stream = new XStream(new XppDriver(new NoNameCoder()) {                @Override                public HierarchicalStreamWriter createWriter(Writer out) {                    return new PrettyPrintWriter(out) {                        // 对所有xml节点的转换都增加CDATA标记                        boolean cdata = true;                        @Override                        @SuppressWarnings("rawtypes")                        public void startNode(String name, Class clazz) {                            super.startNode(name, clazz);                        }                        @Override                        public String encodeNode(String name) {                            return name;                        }                        @Override                        protected void writeText(QuickWriter writer, String text) {                            if (cdata) {                                writer.write("<![CDATA[");                                writer.write(text);                                writer.write("]]>");                            } else {                                writer.write(text);                            }                        }                    };                }            });

输出XML:

<xml>  <appid><![CDATA[123456]]></appid>  <mch_id><![CDATA[1111111]]></mch_id>  <attach><![CDATA[hehedesk]]></attach>  <body><![CDATA[hehedesk]]></body>  <openid><![CDATA[5654675]]></openid>  <trade_type><![CDATA[JSAPI]]></trade_type>  <sign><![CDATA[0000000000000000]]></sign>  <device_info><![CDATA[WEB]]></device_info></xml>
2 0