昨天用java写一个xml序列化成json的递归算法的时候遇到一个问题,遇到一个问题,就是用class做xml的元素或者属性的节点序列化不成功。后来,单步调试的时候,发现数据其实是从xml中读出来了的,并且存入了json对象中,但是在返回的时候没有返回成功。下面是xml序列化成json的方法:
1 /** 2 * 迭代某元素,属性,文本,及下级元素,并将其转换为json对象 3 */ 4 public static JSONObject xmlToJson(Element e){ 5 JSONObject json=new JSONObject(); 6 //查看是否有文本数据 7 String text=e.getTextTrim(); 8 if (text.length()!=0) { 9 json.put(R.S.TEXT,text); 10 } 11 //查看元素是否有属性 12 List<Attribute> attrs=e.attributes(); 13 for (Attribute attr : attrs) { 14 json.put(attr.getName(),attr.getValue()); 15 } 16 //查看元素是否包含元素 17 List<Element> es=e.elements(); 18 for (Element ele : es) { 19 List<Element> elecount=e.elements(ele.getQName()); 20 //说明该元素是唯一的,不做数组处理 21 if (elecount.size()==1) { 22 json.put(ele.getName(),xmlToJson(ele)); 23 } 24 //说明该元素不是唯一的,应该以数组处理 25 if (elecount.size()>1) { 26 //之前已经遍历过了,此次不需要再遍历 27 if (elecount.indexOf(ele)>0) { 28 continue; 29 } 30 JSONArray arr=new JSONArray(); 31 String key=null; 32 for (Element el: elecount) { 33 if (key==null) { 34 key=el.getName(); 35 } 36 arr.add(xmlToJson(el)); 37 } 38 json.put(key,arr); 39 } 40 } 41 return json; 42 }
下面是被测试的xml代码:
1 <!-- 实体类/entity/bean/pojo配置 --> 2 <ll:entitys> 3 <ll:pakage pakage="author.liulang.mybatis.entity"/> 4 <ll:save path="author/liulang/mybatis/entity/"/> 5 <ll:attr equal="public" getter="public" filed="private" hash="public" public="public" serial="true" setter="public" static="false" tostring="public"/> 6 <ll:parent class="author.liulang.common.entity.BasicEntity"/> 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 static void main(String[] args) { 2 XmlUtils.setPath(C.F.X.LiuLang); 3 Element root= XmlUtils.open(); 4 Element entitys = root.element("entitys"); 5 JSONObject json= XmlUtils.xmlToJson(entitys); 6 System.err.println(json); 7 8 }
下面是调用后返回json代码的结果:
1 { 2 "pakage": { 3 "pakage": "author.liulang.mybatis.entity" 4 }, 5 "save": { 6 "path": "author/liulang/mybatis/entity/" 7 }, 8 "attr": { 9 "equal": "public", 10 "getter": "public", 11 "filed": "private", 12 "hash": "public", 13 "public": "public", 14 "serial": "true", 15 "setter": "public", 16 "static": "false", 17 "tostring": "public" 18 }, 19 "parent": {}, 20 "types": { 21 "type": [ 22 { 23 "db": "int", 24 "java": "int" 25 }, 26 { 27 "db": "intunsigned", 28 "java": "int" 29 }, 30 { 31 "db": "integer", 32 "java": "int" 33 }, 34 { 35 "db": "char", 36 "java": "String" 37 }, 38 { 39 "db": "tinyint", 40 "java": "int" 41 }, 42 { 43 "db": "bigint", 44 "java": "long" 45 }, 46 { 47 "db": "date", 48 "java": "java.util.Date" 49 }, 50 { 51 "db": "datetime", 52 "java": "java.util.Date" 53 }, 54 { 55 "db": "varchar", 56 "java": "String" 57 }, 58 { 59 "db": "double", 60 "java": "double" 61 }, 62 { 63 "db": "decimal", 64 "java": "java.math.BigDecimal" 65 }, 66 { 67 "db": "float", 68 "java": "float" 69 }, 70 { 71 "db": "text", 72 "java": "String" 73 }, 74 { 75 "db": "int", 76 "java": "int" 77 } 78 ] 79 } 80 }
通过结果看到,json对象的parent字段为空,而实际该字段的结果应该为{"class":"author.liulang.common.entity.BasicEntity"},不信我们把xml文件的parent元素class属性缓存cls,那么我们可以看到返回的结果中parent字段为:{"cls":"author.liulang.common.entity.BasicEntity"}:
下面是改后的xml代码:
1 <!-- 实体类/entity/bean/pojo配置 --> 2 <ll:entitys> 3 <ll:pakage pakage="author.liulang.mybatis.entity"/> 4 <ll:save path="author/liulang/mybatis/entity/"/> 5 <ll:attr equal="public" getter="public" filed="private" hash="public" public="public" serial="true" setter="public" static="false" tostring="public"/> 6 <ll:parent cls="author.liulang.common.entity.BasicEntity"/> 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>
下面是改后返回的json对象:
1 { 2 "pakage": { 3 "pakage": "author.liulang.mybatis.entity" 4 }, 5 "save": { 6 "path": "author/liulang/mybatis/entity/" 7 }, 8 "attr": { 9 "equal": "public", 10 "getter": "public", 11 "filed": "private", 12 "hash": "public", 13 "public": "public", 14 "serial": "true", 15 "setter": "public", 16 "static": "false", 17 "tostring": "public" 18 }, 19 "parent": { 20 "cls": "author.liulang.common.entity.BasicEntity" 21 }, 22 "types": { 23 "type": [ 24 { 25 "db": "int", 26 "java": "int" 27 }, 28 { 29 "db": "intunsigned", 30 "java": "int" 31 }, 32 { 33 "db": "integer", 34 "java": "int" 35 }, 36 { 37 "db": "char", 38 "java": "String" 39 }, 40 { 41 "db": "tinyint", 42 "java": "int" 43 }, 44 { 45 "db": "bigint", 46 "java": "long" 47 }, 48 { 49 "db": "date", 50 "java": "java.util.Date" 51 }, 52 { 53 "db": "datetime", 54 "java": "java.util.Date" 55 }, 56 { 57 "db": "varchar", 58 "java": "String" 59 }, 60 { 61 "db": "double", 62 "java": "double" 63 }, 64 { 65 "db": "decimal", 66 "java": "java.math.BigDecimal" 67 }, 68 { 69 "db": "float", 70 "java": "float" 71 }, 72 { 73 "db": "text", 74 "java": "String" 75 }, 76 { 77 "db": "int", 78 "java": "int" 79 } 80 ] 81 } 82 }
可以看到这时候json对象的parent字段不再为空,而是{"cls":"author.liulang.common.entity.BasicEntity"},那么我们可以初步得出结论,json对象不能解析key为class的数据,到底是不是这样呢?上面的代码因为涉及到递归,和一些其他相关联的步骤,并不能很好的说明这是json-lib的bug,好的下面我们来做一个进一步验证:
这里我在main方法中写了一段代码如下:
1 public static void main(String[] args) { 2 JSONObject json=new JSONObject(); 3 json.put("class","我用class做了json对象的key"); 4 System.err.println(json); 5 JSONObject json2=new JSONObject(); 6 json2.put("class",json); 7 System.err.println(json2); 8 }
下面做四个选项,你们猜猜答案是什么:
A.{"class":"我用class做了json对象的key"}
{"class":{"class":"我用class做了json对象的key"}}
B.{"class":}
{"class":{}}
C.{"class":"我用class做了json对象的key"}
{"class":{}}
D.{"class":}
{"class":{"class":"我用class做了json对象的key"}}
如果按照正常情况,答案是A,可是用了关键字class作为key,答案确奇迹般的变成了C,这可以说是json-lib的一个bug了吧,我测试了其它部分关键字,尚未发现该现象。至于造成这种结果的原因还不明确,估计是因为json-lib中用过反射的缘故。
通过这个问题也给我们提个醒:在编程中,定义字符串,变量名,属性名,元素名,方法名的时候虽然要做到见名知意,但是也应该尽量避免与系统中保留关键字,或者是重要关键字重名,遇到这种情况最好是采用该词的简写或者同义词代替,不然在编程中可能给我们带来不必要的麻烦,与此类似的问题,还比如JavaScript中,如果你定义的一个方法名恰好为accept,而且单独定义在一个js文件中,你会发现在调用该方法的时候,浏览器会报错,说这不是一个方法。accept我查过不是JavaScript关键字,其中的原因多半应该是与系统全局方法名或者属性名重复了,或者是与header头有冲突。