您的当前位置:首页正文

json

2021-09-24 来源:步旅网
2009-09-06

JSON — JSON入门与实战详解 —— JavaScript、Java与JSON互转

文章分类:Web前端

JSON入门

什么是JSON

JSON(JavaScript Object Notation http://www.json .org/json -zh.html ),是一种轻量级的基于文本且独立于语言的数据交换格式,比XML更轻巧,它是XML数据交换的一个替代方案。它源于ECMAScript程序语言标准- 第3版(ECMA-262 3rd Edition - December 1999)的子集,定义了便于表示结构化数据的一套格式规范,JSON规范是符合ECMAScript语法规范,这样按JSON规范描述出的字符串已是 JavaScript的原生代码串,这使之能通过eval动态的在JSON串与JavaScript对象之间进行转换。如果夸大来说,它是另一种理想的但 有别于XML数据交换语言。

JSON建构于两种结构

“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表 (hash table),有键列表(keyed list),或者关联数组 (associative array)。

值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为 可能。

JSON语法规则

对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。

值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。

字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串 (character string)。与C或者Java的字符串非常相似。

快速浏览JSON与XML表现形式

假如有一个employee对象,它有“姓、名、员工编号、头衔”等信息,先看看JSON是如何来描述它的: Js代码

1. {

2. employee : 3. {

4. firstName: \"John\5. lastName : \"Doe\6. employeeNumber : 123, 7. title : \"Accountant\" 8. } 9. }

再来看看XML是如何表示的,请看: Xml代码

1.

2. John 3. Doe

4. 123 5. Accountant 6.

从上面描述看,JSON表示法不正是JavaScript中对象描述的一种方式么?正确,这正是JavaScript中的对象构造的原生代码。既然是原生 代码,我们把

它转换成JavaScript中的对象,这样我们操作对象就比操作字符串方便多了。 把JSON字符串转换成JavaScript对象: Js代码

1.

看完上述后我们来对比它们。

XML与JSON比对

经过一番快速浏览后如何?感觉到没有JSON的设计上比XML更轻巧简洁?先前就说过了,正是它符合JavaScript语言对象本身特点,这使得如果服 务器传来的文本是符合JavaScript语法定义语句的字符串,那岂不是一条eval方法就能解析了?的确如此~

从上面两者的表示来看,JSON表示法在语法上要比XML要简洁的多,由于不需要使用关闭标签来呼应开始标签,因此许多多余的信息不再出现了,相对XML 而言基本上不存在数据冗余,这在传输与响应速度上大在提高了。 另外,JSON不只是在表现形式上有如此的优势,最重要的是可以丢弃以前弄得我们晕头转向的DOM解析了(客户端的JavaScript的XML DOM解析,服务器端的DOM、SAX、Dom4j、Jdom等)。JSON与XML相比对JavaScript有着更好

的通用性,一段JSON格式数据 经过JavaScript一个简单的方法(eval)即可转换成 JavaScript对象供程序调用,转换方法是浏览器的JavaScript内部定义好的无需再手工编写。而一段XML格式的数据需要调用浏览器内部的 XML解析器工具进行解析后才可以使用。而对于不同内核的浏览器(如IE、Netscape等)XML解析的方法是有差别的,因此需要针对不同浏览器内核 做不同的方法封装,从而给客户端开发带来一定的复杂度。相比之下JSON被浏览器解析的速度更快。在服务器端不同的语言也有不同的JSON解析器,可以很 方便的解析客户端传过来的字符串,而不像为了读取XML还是借助于这样或那样的API工具。

JSON优缺点

优点:

乍看上去,使用JSON的数据分隔符的优点可能并不那么明显,但存在一个根本性的缘由:它们简化了数据访问。使用这些数据分隔符时, JavaScript引擎对数据结构(如字符串、数组、对象)的内部表示恰好与这些符号相同。

JSON的另一个优点是它的非冗长性。在XML中,打开和关闭标记是必需的,这样才能满足标记的依从性;而在JSON中,所有这些要求 只需通过一个简单的括号即可满足。在包含有数以百计字段的数据交换中,传统的XML标记将会延长数据交换时间

此外,JSON受到了擅长不同编程语言的开发人员的青睐。这是因为无论在Haskell中或 Lisp中,还是在更为主流的C#和Java中,开发都可以方便地生成JSON。

不足:

和许多好东西都具有两面性一样,JSON的非冗长性也不例外,为此JSON丢失了XML具有的一些特性。命名空间允许不同上下文中的相同的信息 段彼此混合,然而,显然在JSON中已经找不到了命名空间。JSON与XML的另一个差别是属性的差异,由于JSON采用冒号赋值,这将导致当XML转化 为 JSON时,在标识符(XML CDATA)与实际属性值之间很难区分谁应该被当作文本考虑。 另外,JSON片段的创建和验证过程比一 般的XML稍显复杂。从这一点来看,XML在开发工具方面领先于JSON。

JSON实践

预备知识

动态脚本函数eval ()

在进一步学习之前,我们有必要讲解一下eval方法的用法,懂的同学可以跳过。

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。它接收一个参数s,如果s不是字符串,则直接返回s。否则执行s语句。如果s语句执行结果是一个值,则直接返回此值,否则返回undefined。

另外,该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此请不要为 eval() 函数传递 String 对象来作为参数: Js代码

1. var str = new String(\"alert('msg')\");

2. //请不要传递String对象,否则直接返回string对象了 3. alert(eval(str)==str);//true 4.

5. //应该传递原始string字符串,这样才看作JavaScript脚本并执行 6. eval(\"alert('msg')\");//msg

最后,需要特别注意的是对象声明语法“{}”并不能返回一个值,需要用括号括起来才会返回值(括号里的脚本是表达式,有返回值,而不是无返回值的逻辑式, 因为大括号里的脚本又可能是表达式,又可能是普通的逻辑表达,所以用小括号括起来后明确的说明是值表达式): Js代码

1. var str=\"{}\";//花括号内没属性时

2. alert(eval('(' + str + ')'));//弹出:[object Object] 3. alert(eval(str));//弹出:undefined 4.

5. str=\"{name:'jzj'}\";// 花括号内有一个属性

6. alert(typeof eval('(' + str + ')'));//弹 出:object,以对象方式返回

7. alert(eval(str));//弹出:jzj

8. alert(eval('(' + str + ')').name);//弹出:jzj 9. alert(eval(str).name);//弹出:undefined 10.

11.str=\"{name:'jzj',age:30}\";//花括号内有多个属性时 12.alert(eval('(' + str + ')'));//

13.alert(eval('(' + str + ')').name);//jzj 14.alert(eval('(' + str + ')').age);//30

15.//alert(eval(str));//运行时会出错,多个属性时不用小括号运行出错 可以看到,对于对象声明语句来说,仅仅是执 行,并不能返回值 。为了返回常用的“{}”这样 的对象声明语句,必须用括号括住,以将其转换为表达式,才能返回其值 。这也是使用JSON来进行Ajax开发的基本原理之一。

现来说说本节的重点,就是在应用eval时,动态脚本所生成的变量都

局部的,但很多时候我们 可能在调用eval函数的外面使用生成的变量,eval

不可能在全局空间内执行,这就给开发带来了不少问题,这该如何作?请看继续往下看吧。

我们先来证实一下eval产生的变量是局部性的,在调用eval函数外是不能访问到此变量的。 Js代码

1. var str='全局';//定义一个全局变量 2. function test(){

3. eval('var str=\"局部\"'); 4. alert(str);//局部 5. }

6. test();

7. alert(str); //弹出:全局

另外,eval生成的函数也是局部的,它只能在生成它的函数内使用,出函数域就不能调用的到。

解决办法: Js代码

1. function gloablEval(code){

2. if(window.attachEvent && !window.opera){ 3. //ie

4. execScript(code); 5. }else{

6. //not ie window对象不能省,否则生成的变量在执行的函数外不可见

7. window.eval(code); 8. alert(str);//局部 9. //eval(code);

10. //alert(str);//局部 11. } 12.}

13.var str='全局';//定义一个全局变量 14.gloablEval('var str=\"局部\"');

15.alert(str); //弹出:局部,这里用局部的履盖了全局变量的值 现解释一下:

1、对于IE浏览器,默认已经提供了这样的函数:execScript,用于在全局空间执行代码。

2、对于Firefox浏览器,直接调用eval函数,则在调用者的空间执行;如果调用 window.eval则在全局空间执行。

JavaScript中的JSON

我们知道,可以使用eval()方法调用JavaScript的编译器把JSON文本转变成对象。因为JSON是JavaScript的一个确切的子集, 编译器可以正确地解析JSON文本,然后生成一个对象结构。 Js代码

1. var myObject = eval('(' + myJSONtext + ')');

eval函数非常快速。它可以编译执行任何JavaScript程序,因此产生了安全性问题。当使用可信任与完善的源代码时才可以使用eval函数。这样 可以更安全的使用JSON解析器。使用XMLHttpRequest的web应用,页面之间的通讯只允许同源,因此是可以信任的。但这却不是完善的。如果 服务器没有严谨的JSON编码,或者没有严格的输入验证,那么可能传送包括危险脚本的无效JSON文本。eval函数将执行恶意的脚本。

如果关心安全的话,使用JSON解析器可以防止此类事件。JSON解析器只能辨识JSON文本,拒绝所有脚本,因此它比较安全,JSON官方网站提供的一 个开源的JSON解析器和字符串转换器(http://www.json.org/json.js )。 Js代码

1. var myObject = myJSONtext.parseJSON();

而JSON的字符串转换器(stringifier)则作相反的工作,它将JavaScript数据结构转换为JSON文本。JSON是不支持循环数据结 构的,所以注意不能把循环的结构交给字符串转换器。 Js代码

1. var myJSONText = myObject.toJSONString();

Java中的JSON

Java中的JSON解释器官方提供了好几种,我们这里使用的是org.json 包,关于如何使用,请参见另一篇《JSON之org.json包测试》 ,它是基于官方包提供的测试改写而来的。

开始实战

本实例实现了客户端与服务器端通过JSON进行参数的传递与接收,而不是通过原来的XML方式进行通信。页面采用了Prototype的Ajax方式进行 异步通信,并采用了官方json.js 进行对象与JSON串的灵活互转。服务器端采用了官方提供org.json 包进行JSON串与Java对象的互转。具体的细节请看代码注释。

客户端实现:

页面代码清单代码

1. 2.

3. JSON Address Book 4.

5. 6.

7.

8.

9.

10. 11. 88. 89.

页面展示结果:

JSON Address Book 服务器返回的JSON串如下: {\"addressbook\": [ { \"address\": { \"city\": [ \"Seattle, WA\ \"changsha\" ], \"street\": [\"P.O BOX 54534\"], \"zip\": [42452] }, \"name\": \"Ann Michaels\ \"phoneNumbers\": [ \"561-832-3180\ \"531-133-9098\" ] }, { \"address\": { \"city\": [ \"Miami, FL\ \"changsha\" ], \"street\": [\"53 Mullholand Drive\"], \"zip\": [72452] }, \"name\": \"Betty Carter\ \"phoneNumbers\": [ \"541-322-1723\ \"546-338-1100\" ] } ]} 从 JSON对象提取信息如下: Name: Ann Michaels Address: P.O BOX 54534 -- Seattle, WA,42452. Telephone numbers: 561-832-3180 & 531-133-9098. Name: Betty Carter Address: 53 Mullholand Drive -- Miami, FL,72452. Telephone numbers: 541-322-1723 & 546-338-1100. 服务器端实现:

Java代码

1. package orgjson; 2.

3. import java.io.IOException; 4. import java.util.Iterator; 5. import java.util.Map;

6. import java.util.SortedMap; 7. import java.util.TreeMap; 8.

9. import javax.servlet.ServletException; 10.import javax.servlet.http.HttpServlet;

11.import javax.servlet.http.HttpServletRequest; 12.import javax.servlet.http.HttpServletResponse; 13.

14.import org.json.JSONArray; 15.import org.json.JSONException; 16.import org.json.JSONObject; 17.

18.import bean.Address; 19.

20./**

21. * 使 用 org.josn 包进行解析操作 22. * (C) 2009-9-1, jzjleo 23. */

24.public class AddressServlet extends HttpServlet { 25.

26. private static final long serialVersionUID = -1762985503942785440L; 27.

28. protected void service(HttpServletRequest req, HttpServletResponse resp)

29. throws ServletException, IOException { 30. // 创建addressbook数据结构

31. SortedMap addressBook = new TreeMap(); 32.

33. // 创建新的address实体并放置到Map中

34. Address annMichaels = new Address(\"P.O BOX 54534tle, WA\

35. \"561-832-3180\

36. addressBook.put(\"Ann Michaels\37.

38. Address bettyCarter = new Address(\"53 Mullholand Drive\", \"Miami, FL\

39. \"541-322-1723\

40. addressBook.put(\"Betty Carter\41.

42. try { 43.

44. // 准备转换通讯簿映射到JSON数组 45. // 数组用于放置多个地址条目

46. JSONArray jsonAddressBook = new JSONArray(); 47.

48. // 迭代过滤地址簿条目

49. for (Iterator iter = addressBook.entrySet().iterator(); iter.hasNext();) { 50.

51. // 找当前迭代项

52. Map.Entry entry = (Map.Entry) iter.next(); 53. String key = (String) entry.getKey();

54. Address addressValue = (Address) entry.getValue(); 55.

56. // 以键值对的形式存入条目并分配给\"name\" 57. JSONObject jsonResult = new JSONObject();

58. jsonResult.put(\"name\59.

60. // 获取和创造相应的地址结构,綁定到新Key 61. // 追加地址条目到JSON格式结果

62. String streetText = addressValue.getStreet(); 63. String cityText = addressValue.getCity(); 64. int zipText = addressValue.getZip(); 65.

66. //--注:Bean可以直接转换成JSON串,下面可以采 用 new JSONObject(addressValue)

67. //形式来自动转换成JSON串

68. JSONObject jsonAddrObj = new JSONObject(); 69.

70. //以数组的形式存放,street为存放数组的变量名即Key,如果key不存在,则新建,如果存在, 71. //则在原来数组后追加 72.

73. //jsonAddress.append(\"street\74. //上句等价于下面语句

75. jsonAddrObj.put(\"streetreetText));

76. jsonAddrObj.append(\"city\

77. jsonAddrObj.append(\"city\追加 78. //上两句等价于如下语句

79. //jsonAddrObj.put(\"city\cityText).put(\"changsha\"));

80. jsonAddrObj.append(\"zip\;

81. jsonResult.put(\"address\82.

83. // 获取和结构,建立相应的电话到新的Key 84. // 追加在电话条目到JSON格式的结果里 85. String telText = addressValue.getTel();

86. String telTwoText = addressValue.getTelTwo(); 87. JSONArray jsonTelephones = new JSONArray(); 88. jsonTelephones.put(telText); 89. jsonTelephones.put(telTwoText);

90. jsonResult.put(\"phoneNumbers\ 91.

92. // 把JSON地址条目放置到全局的JSON地址薄数组里

93. jsonAddressBook.put(jsonResult); 94. } // 结束循环地址薄

95.

96. // 赋值JSON地址薄到结果字符变量

97. JSONObject resultJsonObj = new JSONObject().put(\"addressbook\

98. jsonAddressBook); 99.

100. //格式化输出到页面上的JSON串

101. String jsonHtmlStr = resultJsonObj.toString(4).replaceAll(\" \

102. .replaceAll(\"\\n\103.

104. JSONObject jsonObj = new JSONObject().put(\"jsonHtmlStr\

105. \"jsonCode\

106. // 返回JSON串

107. resp.getOutputStream().write(jsonObj.toString().getBytes()); 108.

109. System.out.println(resultJsonObj.toString(4));

110. //System.out.println(jsonObj.toString(4)); 111. System.out.println(\"-----------------------------------------------\");

112. readJSONString(req); 113. } catch (Exception e) { 114. e.printStackTrace(); 115. } 116.

117. } 118.

119. /**

120. * 从 客户端读取JSON串 121. * @param req 122. */

123. public void readJSONString(HttpServletRequest req) { 124. System.out.println(\"接收到客户端的JSON信息如下:\");

125. JSONObject clientJSONObj; 126. try {

127. clientJSONObj = new JSONObject(req.getParameter(\"jsonStr\")); 128.

129. System.out.println(clientJSONObj.toString(4));

130. JSONArray addressbookArray = clientJSONObj.getJSONArray(\"addressbook\");

131. for (int i = 0; i < addressbookArray.length(); i++) {

132. System.out.println(\"The\" + \" \" + (i + 1) + \" addressbook msg:\");

133. JSONObject addressbookJSONObj = addressbookArray.getJSONObject(i);

134. JSONObject addressJSONObj = addressbookJSONObj.getJSONObject(\"address\");

135. System.out.println(\"address-------\"); 136. System.out.println(\" \" + addressJSONObj.getString(\"city\"));

137. System.out.println(\" \" + addressJSONObj.getString(\"street\"));

138. System.out.println(\" \" + addressJSONObj.getString(\"zip\"));

139. System.out.println(\"name----------\"); 140. System.out.println(\" \" + addressbookJSONObj.getString(\"name\"));

141. System.out.println(\"phoneNumbers--\"); 142. JSONArray phoneNumbersArr = addressbookJSONObj

143. .getJSONArray(\"phoneNumbers\"); 144. System.out.println(\" \" + phoneNumbersArr.getString(0));

145. System.out.println(\" \" + phoneNumbersArr.getString(1));

146. System.out.println(); 147. }

148. } catch (JSONException e) { 149. e.printStackTrace(); 150. } 151. } 152. }

服务器后台打印:

{\"addressbook\": [ {

\"address\": { \"city\": [

\"Seattle, WA\ \"changsha\" ],

\"street\": [\"P.O BOX 54534\"], \"zip\": [42452] },

\"name\": \"Ann Michaels\ \"phoneNumbers\": [ \"561-832-3180\ \"531-133-9098\" ] }, {

\"address\": { \"city\": [

\"Miami, FL\ \"changsha\" ],

\"street\": [\"53 Mullholand Drive\"], \"zip\": [72452] },

\"name\": \"Betty Carter\ \"phoneNumbers\": [ \"541-322-1723\ \"546-338-1100\" ] } ]}

----------------------------------------------- 接 收到客户端的JSON信息如下: {\"addressbook\": [ {

\"address\": {

\"city\": \"Seattle, WA\ \"street\": \"P.O BOX 54534\ \"zip\": 42452 },

\"name\": \"Ann Michaels\ \"phoneNumbers\": [ \"561-832-3180\ \"531-133-9098\"

] }, {

\"address\": {

\"city\": \"Miami, FL\

\"street\": \"53 Mullholand Drive\ \"zip\": 72452 },

\"name\": \"Betty Carter\ \"phoneNumbers\": [ \"541-322-1723\ \"546-338-1100\" ] } ]}

The 1 addressbook msg: address-------

Seattle, WA P.O BOX 54534 42452 name----------

Ann Michaels phoneNumbers--

561-832-3180 531-133-9098

The 2 addressbook msg: address-------

Miami, FL

53 Mullholand Drive 72452 name----------

Betty Carter phoneNumbers--

541-322-1723 546-338-1100

因篇幅问题不能全部显示,请点此查看更多更全内容