微信支付开发教程JAVA编[003]-json和xml的解析

来源:互联网 发布:品茗网络计划2014破解 编辑:程序博客网 时间:2024/04/30 22:00

        我承接app微信公众号开发,如果有谁需要的话,可以惠顾我,谢谢.

QQ: 40678884

微信: szuzsq

主页: http://www.wxshaker.com

博客: http://blog.csdn.net/szuzsq

-------------------------------------------------------------------------------------------------------------------------------------



        注:我已经使用java语言将微信公众号和微信支付开发的所有API功能点都调用测试过一次,后期会在博客中其享给大家.在接下来的这几篇文章中,都是基于我的这个wxsdk4j,有些代码可能在单独的章节中,运行不起来,没问题,等我将所有的章节讲完,共享了wxsdk4j,就能跑起来了,大家别着急,请耐心等待.


        调用微信公众号高级接口,需要将数据以json形式提交到微信服务器上,并且在消息会话过程中,微信服务器会以xml的形式转发消息到公众号自己的服务器上.同时调用微信支付接口也需要将数据以xml的形式提交到微信服务器上.这里,我们就讲讲在java中,怎么解析与生成json和xml.


一.json的解析与生成

        json的官方网站是:http://www.json.org,在这里,实现了各种语言并且每种语言又有多种版本.我使用的是JSON-Java,它的官方网站是:https://github.com/stleary/JSON-java,下载下来是源码,大家可以制作成jar包,在我的wxsdk4j中,就已经制作成了附带源码的jar包.

        JSON-Java最主要是JSONObject,JSONArray(另外,有一个JSONObject.NULL类,这个类用于处于json中null节点,例如{"name":null}),这2个类很简单,基本就是put和get(请注意get方法在key不存在时,会抛出异常,有一族不抛异常的对应方法,就是opt.我个人极其讨厌java强制使用try catch机制.认识这么多java猿,1个2个都对try catch像色鬼遇上18岁的纯情小姑娘似的,难道就木有1个java猿和我想法一样的么?深求讨厌try catch的java猿,如果是软妹纸,老夫以身相许!!!!!!!!)这2个方法,会用map,list就会用这2个类了.例如,以下代码生成json字符串:

JSONArray array = new JSONArray();array.put("中文");array.put("英文");array.put("法文");JSONObject object = new JSONObject();object.put("name", "kitty");object.put("age", 22);object.put("lang", array);System.out.println(object.toString());

它生成的json如下(为了好看,我排了下版):

{"age": 22,"name": "kitty","lang": ["中文", "英文", "法文"]}

另外,因为put方法返回的是this指针,上面的代码也可以写成链式结构,如下:

System.out.println( //new JSONObject() //.put("name", "kitty") //.put("age", 22) //.put("lang", new JSONArray() //.put("中文") //.put("英文") //.put("法文") //).toString() //);
是不是很有层次感?


解析json字符串就更加简单了,直接传入字符串创建对象就行了.例如:

new JSONObject(str);new JSONArray(str);
稍微注意一下,就是如果字符串不是合法的json字符串,创建对象不成功,会抛出异常(异常又见异常!).


二.xml的解析与生成

        很多人在项目中,都使用xstream,jdom之类的库来解析xml.没有必要.基本库自带的org.w3c.dom已经足够.需要注意的是,很多微信开发人员,使用的好像都是柳峰老大的解析成Map<String, String>的那个函数.其实我想说,xml除了儿子,还有儿子的儿子呢?还有属性呢?虽然属性在微信公众号和微信支付中并不使用.但微信公众号某些事件转发的xml可是有多级节点的,例如摇一摇.周边.下面,给大家一个我封装的工具类,比较万能:

/*************************************************************** * 解析xml ***************************************************************/package wxlib.wxsdk.lib.utils;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Pattern;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import org.json.JSONArray;import org.json.JSONObject;import org.w3c.dom.Attr;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.Text;public class XMLParser {protected static boolean isNull(String str) { //可以匹配JSONObject.NULLif(str == null)return false;str = str.trim();return str.equals("null");}protected static boolean isBoolean(String str) {if(str == null)return false;str = str.trim();return str.equals("false") || str.equals("true");}protected static boolean isNumeric(String str) { //include int and floatif(str == null)return false;str = str.trim();//.     匹配除换行符以外的任意字符//\w    匹配字母或数字或下划线或汉字//\s    匹配任意的空白符//\d    匹配数字//\b    匹配单词的开始或结束//^     匹配字符串的开始//$     匹配字符串的结束//----------------------------------//*     重复零次或更多次//+     重复一次或更多次//?     重复零次或一次//{n}   重复n次//{n,}  重复n次或更多次//{n,m} 重复n到m次Pattern pattern = Pattern.compile("^[-\\+]?\\d*.?\\d+$"); //-100.02 //-.08return pattern.matcher(str).matches();}protected static boolean isInteger(String str) {if(str == null)return false;str = str.trim();//.     匹配除换行符以外的任意字符//\w    匹配字母或数字或下划线或汉字//\s    匹配任意的空白符//\d    匹配数字//\b    匹配单词的开始或结束//^     匹配字符串的开始//$     匹配字符串的结束//----------------------------------//*     重复零次或更多次//+     重复一次或更多次//?     重复零次或一次//{n}   重复n次//{n,}  重复n次或更多次//{n,m} 重复n到m次Pattern pattern = Pattern.compile("^[-\\+]?\\d+$"); //-100return pattern.matcher(str).matches();}protected static boolean isFloat(String str) {if(str == null)return false;str = str.trim();//.     匹配除换行符以外的任意字符//\w    匹配字母或数字或下划线或汉字//\s    匹配任意的空白符//\d    匹配数字//\b    匹配单词的开始或结束//^     匹配字符串的开始//$     匹配字符串的结束//----------------------------------//*     重复零次或更多次//+     重复一次或更多次//?     重复零次或一次//{n}   重复n次//{n,}  重复n次或更多次//{n,m} 重复n到m次Pattern pattern = Pattern.compile("^[-\\+]?\\d*.\\d+$"); //-100.02 //-.08return pattern.matcher(str).matches();}/**protected static boolean isString(String str) {return true;}protected static boolean isObject(String str) {return true;}protected static boolean isArray(String str) {return true;}*/protected static class ParseResult {public List<Object> text = null;public JSONObject map = null;}protected static Object parseValue(String str) {if(isNull(str))return JSONObject.NULL;else if(isBoolean(str))return Boolean.parseBoolean(str);else if(isInteger(str)) {try {return Long.parseLong(str);}catch(Exception e) {return str; //数字太长}}else if(isFloat(str))return Double.parseDouble(str);elsereturn str;}/** * 解析节点 * @param node $node 节点 * @return ParseResult 结果集 */protected static ParseResult parseNode(Node node) {List<Object> text = null; //当前文本JSONObject map = null; //当前节点NamedNodeMap attrs = node.getAttributes();for(int i = 0; attrs != null && i < attrs.getLength(); i++) {Node item = attrs.item(i);if(item == null)continue;String name = item.getNodeName() != null ? item.getNodeName().trim() : "";String value = item.getNodeValue() != null ? item.getNodeValue().trim() : "";if(name.equals(""))continue;if((item instanceof Attr)) {if(map == null)map = new JSONObject();map.put("@" + name, parseValue(value)); //属性形式为:{"@id": 1}}}Map<String, List<ParseResult>> result = new HashMap<String, List<ParseResult>>(); //子节点NodeList list = node.getChildNodes();for(int i = 0; list != null && i < list.getLength(); i++) {Node item = list.item(i);if(item == null)continue;String name = item.getNodeName() != null ? item.getNodeName().trim() : "";String value = item.getNodeValue() != null ? item.getNodeValue().trim() : "";if(name.equals(""))continue;if(item instanceof Text && !value.equals("")) {if(text == null)text = new ArrayList<Object>();text.add(parseValue(value));}if(item instanceof Element) {if(map == null)map = new JSONObject();ParseResult child = parseNode(item);if(child != null) {List<ParseResult> l = result.get(name);if(l == null)l = new ArrayList<ParseResult>();l.add(child);result.put(name, l);}}}if(text == null && map == null) { //空节点:<node></node>text = new ArrayList<Object>();text.add("");}for(Map.Entry<String, List<ParseResult>> entry : result.entrySet()) { //处理子节点的textString name = entry.getKey() != null ? entry.getKey() : "";List<ParseResult> l = entry.getValue();if(name.equals("") || l == null)continue;if(l.size() == 1) { //映射表里只有一个相同名字的子节点ParseResult value = l.get(0);if(value != null) {if(value.map == null) { //没有属性等if(value.text != null && value.text.size() == 1) { //没有属性等,只有一个textif(map == null)map = new JSONObject();map.put(name, value.text.get(0));}else if(value.text != null && value.text.size() > 1) { //没有属性等,有多个textif(map == null)map = new JSONObject();map.put(name, new JSONArray(value.text));}}else if(value.map != null) { //有属性等if(value.text != null && value.text.size() == 1) { //有属性等,只有一个textvalue.map.put("#text", value.text.get(0));}else if(value.text != null && value.text.size() > 1) { //有属性等,有多个textvalue.map.put("#text", new JSONArray(value.text));}if(map == null)map = new JSONObject();map.put(name, value.map);}}}//------------------------------------------------------------------else if(l.size() > 1) { //映射表里有多个相同名字的子节点JSONArray array = (map != null && map.optJSONArray(name) != null) ? map.optJSONArray(name) : new JSONArray();for(ParseResult value : l) {if(value == null)continue;if(value.map == null) { //没有属性等if(value.text != null && value.text.size() == 1) { //没有属性等,只有一个textarray.put(value.text.get(0));}else if(value.text != null && value.text.size() > 1) { //没有属性等,有多个textarray.put(new JSONArray(value.text));}}else if(value.map != null) { //有属性等if(value.text != null && value.text.size() == 1) { //有属性等,只有一个textvalue.map.put("#text", value.text.get(0));}else if(value.text != null && value.text.size() > 1) { //有属性等,有多个textvalue.map.put("#text", new JSONArray(value.text));}array.put(value.map);}}if(map == null)map = new JSONObject();map.put(name, array);}}ParseResult rs = new ParseResult();rs.text = text;rs.map = map;return rs;}protected static String serialArray(String name, JSONArray node) {name = name != null ? name.trim() : "";if(name.equals(""))return "";String sub = ""; //子节点for(int i = 0; i < node.length(); i++) {Object value = node.opt(i);if(value == null)continue;if(value instanceof JSONObject) {sub += serialObject(name, (JSONObject)value);}else if(value instanceof JSONArray) {sub += serialArray(name, (JSONArray)value);}else {String t = value.toString().trim();sub += (t.equals("") || isNull(t) || isBoolean(t) || isNumeric(t)) ? String.format("<%s>%s</%s>", name, t, name) : String.format("<%s><![CDATA[%s]]></%s>", name, t, name);}}return sub;}protected static String serialObject(String name, JSONObject node) {name = name != null ? name.trim() : "";if(name.equals(""))return "";String attr = ""; //属性String text = ""; //文本String sub = ""; //子节点for(String key : node.keySet()) {if(key == null)continue;Object value = node.opt(key);if(value == null)continue;key = key.trim();if(key.startsWith("@")) { //属性为:{"@id": 2}key = key.substring(1);if(key.equals(""))continue;attr += String.format(" %s='%s'", key, value.toString());}else if(key.equals("#text")) {if(value instanceof JSONArray) {JSONArray array = (JSONArray)value;for(int i = 0; i < array.length(); i++)text += array.opt(i);}elsetext += value.toString();}else if(value instanceof JSONObject) {sub += serialObject(key, (JSONObject)value);}else if(value instanceof JSONArray) {sub += serialArray(key, (JSONArray)value);}else {String t = value.toString().trim();sub += (t.equals("") || isNull(t) || isBoolean(t) || isNumeric(t)) ? String.format("<%s>%s</%s>", key, t, key) : String.format("<%s><![CDATA[%s]]></%s>", key, t, key);}}text = text.trim();String xml = (text.equals("") || isNull(text) || isBoolean(text) || isNumeric(text)) ? String.format("<%s%s>%s%s</%s>", name, attr, text, sub, name) : String.format("<%s%s><![CDATA[%s]]>%s</%s>", name, attr, text, sub, name);return xml;}/** * array参数转化为xml字符串数据 * 注:xml中null解析为JSONObject.NULL * <xml> *     <n>null</n> <!-- 解析为JSONObject.NULL --> *     <b>true</b> *     <f>20.8</f> *     <i>20</i> *     <s><![CDATA[hello]]></s> * </xml> * 转化为json为: * { *     "n": null, *     "b": true, *     "f": 20.8, *     "i": 20, *     "s": "hello" * } * @param jsonobject $map 要转换的映射表 * @return string 转换后的xml字符串数据 */public static String toXml(JSONObject map) {String xml = serialObject("xml", map);return xml;}/** * xml字符串数据转化为array参数 * 注:xml中null解析为JSONObject.NULL * <xml> *     <n>null</n> <!-- 解析为JSONObject.NULL --> *     <b>true</b> *     <f>20.8</f> *     <i>20</i> *     <s><![CDATA[hello]]></s> * </xml> * 转化为json为: * { *     "n": null, *     "b": true, *     "f": 20.8, *     "i": 20, *     "s": "hello" * } * @param string $str 要转换的xml字符串数据 * @return jsonobject 转换后的映射表 */public static JSONObject fromXml(String str) {//解析根节点:"<xml></xml>".但是忽略xml头,如:"<?xml version='1.0' encoding='UTF-8'?>"Node root = null;try {InputStream stream = new ByteArrayInputStream(str.getBytes());try {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(stream);root = document.getFirstChild();}catch(Exception e) {}stream.close();}catch(Exception e) {}if(root == null)return new JSONObject();ParseResult value = parseNode(root);if(value.map == null)value.map = new JSONObject();//处理根节点的textif(value.text != null && value.text.size() == 1) { //有属性等,只有一个textvalue.map.put("#text", value.text.get(0));}else if(value.text != null && value.text.size() > 1) { //有属性等,有多个textvalue.map.put("#text", new JSONArray(value.text));}return value.map;}}

大家不用着急,这个类,会随着我的wxsdk4j一起发布.

使用方法很简单.例如:

String str = "<xml>";str += "<name>kitty</name>";str += "<age>22</age>";str += "<lang>中文</lang>";str += "<lang>英文</lang>";str += "<lang>法文</lang>";str += "<attr id='2'></attr>";str += "<extend id='10'>哈佛大学</extend>";str += "</xml>";//解析xml字符串成JSONObject对象JSONObject object = XMLParser.fromXml(str);System.out.println(object.toString());String name = object.optString("name");int age = object.optInt("age");String lang0 = object.optJSONArray("lang").optString(0);String lang1 = object.optJSONArray("lang").optString(1);String lang2 = object.optJSONArray("lang").optString(2);String attr_id = object.optJSONObject("attr").optString("@id");String extend_id = object.optJSONObject("extend").optString("@id");String extend_text = object.optJSONObject("extend").optString("#text");System.out.println(name);System.out.println(age);System.out.println(lang0);System.out.println(lang1);System.out.println(lang2);System.out.println(attr_id);System.out.println(extend_id);System.out.println(extend_text);//由JSONObject对象生成xml字符串System.out.println(XMLParser.toXml(object));

如果如下:

{"extend": {"#text": "哈佛大学","@id": 10},"name": "kitty","age": 22,"attr": {"@id": 2},"lang": ["中文", "英文", "法文"]}

kitty22中文英文法文210哈佛大学

<xml><extend id='10'><![CDATA[哈佛大学]]></extend><name><![CDATA[kitty]]></name><age>22</age><attr id='2'></attr><lang><![CDATA[中文]]></lang><lang><![CDATA[英文]]></lang><lang><![CDATA[法文]]></lang></xml>


需要注意的是:

1).在解析属性时,在属性名称前面添加了"@",以区别文本内容.例如"@id",

2).如果只有文本内空,则直接映射成了键值对.如果有属性或子节点,又有文本内容,则将文本内容映射成"#text".这也是jdom还是哪个库里的做法.

3).为了适应微信,生成xml时,字符串的文本,作为CDATA节点.








0 0