之前找了一个json-lib的bug,里面展示了一段遍历xml并将其转换为json的算法,今天就来说说这个算法,这个算法所用到的东西就是所谓的递归算法,虽然在程序中不建议用递归算法。
递归算法的特点:
1.递归就是在过程或函数里调用自身
2. 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
如果不满足第一点就不叫递归,如果不满足第二点,那么将会永无结束条件,直到崩溃。有人说盗梦空间就是一个递归,每一层梦境就是一层递归,然后每一层时间就比上一层慢20倍,盗梦空间要结束的条件就是duang一下(坠击)
然后,再说说高人给我说的写递归算法的方法:
不要对运行机制深究,就是每一步怎么运行的,不然你会被递归进去,你要做的是把这一层可能的所有情况考虑清楚就行了,如果这一层情况考虑完了不知道怎么处理的时候,交给下一层处理,如果这一层可能的情况没有考虑完,那么就等着程序报错,再来找,还有考虑的时候从结束条件开始考虑,然后考虑最简单的情况。
下面是测试的xml:
1 <ll:entitys> 2 <ll:filter dbfiled="name|id|age" dbtable="emp|mgr|account"/> 3 <ll:package package="author.liulang.mgr.mod.entity"/> 4 <ll:parent cls="author.liulang.mgr.mod.inter.ModAdaptor"/> 5 <ll:save path="author/liulang/mgr/mod/entity/"/> 6 <ll:attr public="public" serial="yes" filed="private" static="no" getter="public" setter="public" tostring="public" equals="public" hashcode="public"/> 7 <ll:types> 8 <ll:type db="int" java="int"/> 9 <ll:type db="intunsigned" java="int"/> 10 <ll:type db="integer" java="int"/> 11 <ll:type db="char" java="String"/> 12 <ll:type db="tinyint" java="int"/> 13 <ll:type db="bigint" java="long"/> 14 <ll:type db="date" java="java.util.Date"/> 15 <ll:type db="datetime" java="java.util.Date"/> 16 <ll:type db="varchar" java="String"/> 17 <ll:type db="double" java="double"/> 18 <ll:type db="decimal" java="java.math.BigDecimal"/> 19 <ll:type db="float" java="float"/> 20 <ll:type db="text" java="String"/> 21 <ll:type db="int" java="int"/> 22 </ll:types> 23 </ll:entitys>
下面是最简单的加法递归算法:
1 public class Test { 2 /** 3 * 从1+n的递归算法 4 * @param n 5 * @return 6 */ 7 public static int add(int n){ 8 /* 9 * n的情况一:可能是0,如果是0就该结束了 10 */ 11 if (n==0) { 12 return 0; 13 } 14 /* 15 * 情况二:n不是0,那么n-1之前所有的数之和 16 * 与自己相加,就是n的结果了,至于add方法怎么 17 * 加的我不知道,不陷入进去了 18 */ 19 return n+add(n-1); 20 } 21 public static void main(String[] args) { 22 System.err.println(add(100)); 23 } 24 }
好的,现在讲一下我那个xml序列化成json的算法:
首先,我们xml都是由一个一个节点组成的,而节点的开始 ,我们称之为元素,总的来说xml由节点,由属性,由文本这三部分组成,那么结束条件就是当这个元素没有了文本,没有了属性,没有子元素,三个条件同时满足,就该结束了。
一、找结束条件:
1 public static JSONObject xmlToJson(Element e){ 2 /*建立一个对象,返回json,我们目的是转换为json对象,所以返回的一定是 json格式 ,所以即使有数组的情况也不用去考虑*/ 3 JSONObject json=new JSONObject(); 4 /*查看是否有文本数据,有就放入到text字段中,没有就直接跳过,成为结束条件之一*/ 5 String text=e.getTextTrim(); 6 if (text.length()!=0) { 7 json.put("text",text); 8 } 9 /*查看元素是否有属性,有就放入到json中,以属性名作为字段,属性值作为value,没有就是结束条件之一,直接略过*/ 10 @SuppressWarnings("unchecked") 11 List<Attribute> attrs=e.attributes(); 12 for (Attribute attr : attrs) { 13 json.put(attr.getName(),attr.getValue()); 14 } 15 16 return json; 17 }
上面,把没有文本和没有属性的结束条件列举出来了,下面列举没有子元素的结束条件
1 public static JSONObject xmlToJso(Element e){ 2 JSONObject json=new JSONObject(); 3 //查看是否有文本数据 4 String text=e.getTextTrim(); 5 if (text.length()!=0) { 6 json.put(R.S.TEXT,text); 7 } 8 //查看元素是否有属性 9 @SuppressWarnings("unchecked") 10 List<Attribute> attrs=e.attributes(); 11 for (Attribute attr : attrs) { 12 json.put(attr.getName(),attr.getValue()); 13 } 14 //查看元素是否包含元素 15 @SuppressWarnings("unchecked") 16 List<Element> es=e.elements(); 17 for (Element ele : es) {/*如果es的size为零,将不会进入迭代for循环,那么此时就是结束条件的满足*/ 18 } 19 return json; 20 }
当然,假如子元素不为零,这个程序就应该继续进行下去,但是怎么继续呢?如果子元素不为零,那么可能出现两种情况,第一种:子元素都是不同的,还有种就是子元素可能存在相同的.
那么:都是不同的,我们可以就用普通json存放,有多个相同的我们可以用数组存放。
代码:
public static JSONObject xmlToJso(Element e){ JSONObject json=new JSONObject(); //查看是否有文本数据 String text=e.getTextTrim(); if (text.length()!=0) { json.put(R.S.TEXT,text); } //查看元素是否有属性 @SuppressWarnings("unchecked") List<Attribute> attrs=e.attributes(); for (Attribute attr : attrs) { json.put(attr.getName(),attr.getValue()); } //查看元素是否包含元素 @SuppressWarnings("unchecked") List<Element> es=e.elements(); for (Element ele : es) { @SuppressWarnings("unchecked") List<Element> elecount=e.elements(ele.getQName()); //说明该元素是唯一的,不做数组处理 if (elecount.size()==1) { /*子元素是当前元素的一个重复,所以这里不知道怎么做的交给了下一层*/ json.put(ele.getName(),xmlToJson(ele)); } //说明该元素不是唯一的,应该以数组处理 if (elecount.size()>1) { JSONArray arr=new JSONArray(); String key=null; for (Element el: elecount) { if (key==null) { key=el.getName(); } /**将每个元素的结果放入数组,然后统一放回返回的json中,每个元素仍然是本层的重复,就调用自身了*/ arr.add(xmlToJson(el)); } json.put(key,arr); } } return json; }
好了,这个程序,貌似好像,基本,应该写完了。运行一下:
{ "filter": { "dbfiled": "name|age", "dbtable": "" }, "package": { "package": "author.liulang.mgr.mod.entity" }, "parent": { "cls": "author.liulang.mgr.mod.inter.ModAdaptor" }, "save": { "path": "author/liulang/mgr/mod/entity/" }, "attr": { "public": "public", "serial": "no", "filed": "private", "static": "yes", "getter": "public", "setter": "public", "tostring": "public", "equals": "none", "hashcode": "none" }, "types": { "type": [ { "db": "int", "java": "int" }, { "db": "intunsigned", "java": "int" }, { "db": "integer", "java": "int" }, { "db": "char", "java": "String" }, { "db": "tinyint", "java": "int" }, { "db": "bigint", "java": "long" }, { "db": "date", "java": "java.util.Date" }, { "db": "datetime", "java": "java.util.Date" }, { "db": "varchar", "java": "String" }, { "db": "double", "java": "double" }, { "db": "decimal", "java": "java.math.BigDecimal" }, { "db": "float", "java": "float" }, { "db": "text", "java": "String" } ] } }
好像,貌似,真的,应该没有问题了,绝对?绝对?没有问题了?
额:结果真的是没有什么问题了,反正我是没有测出来什么问题,可是我在调试的时候确发现了一个问题,效率问题,其实我们发现一个type元素就得递归一次,n个type元素就得递归n次,只是因为在json里面存放的key相同,前面递归出来的数据被后一条代替了:
/** * 迭代某元素,属性,文本,及下级元素,并将其转换为json对象 */ public static JSONObject xmlToJson(Element e){ JSONObject json=new JSONObject(); //查看是否有文本数据 String text=e.getTextTrim(); if (text.length()!=0) { json.put("text",text); } //查看元素是否有属性 @SuppressWarnings("unchecked") List<Attribute> attrs=e.attributes(); for (Attribute attr : attrs) { json.put(attr.getName(),attr.getValue()); } //查看元素是否包含元素 @SuppressWarnings("unchecked") List<Element> es=e.elements(); for (Element ele : es) { @SuppressWarnings("unchecked") List<Element> elecount=e.elements(ele.getQName()); //说明该元素是唯一的,不做数组处理 if (elecount.size()==1) { json.put(ele.getName(),xmlToJso(ele)); } //说明该元素不是唯一的,应该以数组处理 if (elecount.size()>1) { JSONArray arr=new JSONArray(); String key=null; for (Element el: elecount) { if (key==null) { key=el.getName(); } arr.add(xmlToJso(el)); } /*这里一条调试输出语句*/ System.err.println(arr); json.put(key,arr); } } return json; }
输出结果:
1 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 2 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 3 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 4 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 5 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 6 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 7 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 8 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 9 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 10 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 11 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 12 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}] 13 [{"db":"int","java":"int"},{"db":"intunsigned","java":"int"},{"db":"integer","java":"int"},{"db":"char","java":"String"},{"db":"tinyint","java":"int"},{"db":"bigint","java":"long"},{"db":"date","java":"java.util.Date"},{"db":"datetime","java":"java.util.Date"},{"db":"varchar","java":"String"},{"db":"double","java":"double"},{"db":"decimal","java":"java.math.BigDecimal"},{"db":"float","java":"float"},{"db":"text","java":"String"}]
可以看到重复输出了13次,就是每一个type元素都要序列化一次,效率代价挺大,所以我们这段代码还得加一个限制条条件,只需要重复一次就可以了
public static JSONObject xmlToJson(Element e){
JSONObject json=new JSONObject();
//查看是否有文本数
String text=e.getTextTrim();
if (text.length()!=0) { json.put(R.S.TEXT,text); } //查看元素是否有属性 @SuppressWarnings("unchecked") List<Attribute> attrs=e.attributes(); for (Attribute attr : attrs) { json.put(attr.getName(),attr.getValue()); } //查看元素是否包含元素 @SuppressWarnings("unchecked") List<Element> es=e.elements(); for (Element ele : es) { @SuppressWarnings("unchecked") List<Element> elecount=e.elements(ele.getQName()); //说明该元素是唯一的,不做数组处理 if (elecount.size()==1) { json.put(ele.getName(),xmlToJson(ele)); } //说明该元素不是唯一的,应该以数组处理 if (elecount.size()>1) { /*之前已经遍历过了,此次不需要再遍历,
注意这个限制条件只能是continue不能是break,
因为break了,就将整个循环给跳了出去,如果type之后还有其他元素,
将遍历不到,而continue只是当次不再循环*/ if (elecount.indexOf(ele)>0) { continue; } JSONArray arr=new JSONArray(); String key=null; for (Element el: elecount) { if (key==null) { key=el.getName(); } arr.add(xmlToJson(el)); } json.put(key,arr); } } return json; }
好了,序列化的递归算法基本写完了,只能是说基本,因为可能某些特殊操作还会出现bug,这只能遇到了才改