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來進行編譯,而是直接返回節點名稱。
@Override
public 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>