什么是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语法规则
<script type="text/javascript">
//使用script本身的函数eval将JSON串解析成对象
var e = eval(
'({' +'employee : ' +'{' +'firstName: "John",' +'lastName : "Doe",' +'employeeNumber : 123,' +'title : "Accountant"' +'}' +'})');
//现在我们可以使用e这个对象了,还可以以点的访问形式来访问对象的属性
alert(e.employee.firstName);
alert(e.employee.lastName);
alert(e.employee.employeeNumber);
alert(e.employee.title);
</script>
快速浏览JSON与XML表现形式
假如有一个employee对象,它有“姓、名、员工编号、头衔”等信息,先看看JSON是如何来描述它的:
js代码:
{
employee :
{
firstName: "John",
lastName : "Doe",
employeeNumber : 123,
title : "Accountant"
}
}
再来看看XML是如何表示的,请看:
xml代码:
<employee>
<firstName>John</firstName>
<lastName>Doe</lastName>
<employeeNumber>123</employeeNumber>
<title>Accountant</title>
</employee>
从上面描述看,JSON表示法不正是JavaScript中对象描述的一种方式么?正确,这正是JavaScript中的对象构造的原生代码。既然是原生代码,我们把它转换成JavaScript中的对象,这样我们操作对象就比操作字符串方便多了。
把JSON字符串转换成JavaScript对象:
js代码:
<script type="text/javascript">
//使用script本身的函数eval将JSON串解析成对象
var e = eval(
'({' +
'employee : ' +
'{' +
'firstName: "John",' +
'lastName : "Doe",' +
'employeeNumber : 123,' +
'title : "Accountant"' +
'}' +
'})'
);
//现在我们可以使用e这个对象了,还可以以点的访问形式来访问对象的属性
alert(e.employee.firstName);
alert(e.employee.lastName);
alert(e.employee.employeeNumber);
alert(e.employee.title);
</script>
看完上述后我们来对比它们。
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 对象来作为参数:
最后,需要特别注意的是对象声明语法“{}”并不能返回一个值,需要用括号括起来才会返回值(括号里的脚本是表达式,有返回值,而不是无返回值的逻辑式,因为大括号里的脚本又可能是表达式,又可能是普通的逻辑表达,所以用小括号括起来后明确的说明是值表达式):
var str="{}";//花括号内没属性时 alert(eval('(' + str + ')'));//弹出:[object Object] alert(eval(str));//弹出:undefined str="{name:'jzj'}";//花括号内有一个属性 alert(typeof eval('(' + str + ')'));//弹出:object,以对象方式返回 alert(eval(str));//弹出:jzj alert(eval('(' + str + ')').name);//弹出:jzj alert(eval(str).name);//弹出:undefined str="{name:'jzj',age:30}";//花括号内有多个属性时 alert(eval('(' + str + ')'));// alert(eval('(' + str + ')').name);//jzj alert(eval('(' + str + ')').age);//30 //alert(eval(str));//运行时会出错,多个属性时不用小括号运行出错
可以看到,对于对象声明语句来说,仅仅是执行,并不能返回值 。为了返回常用的“{}”这样的对象声明语句,必须用括号括住,以将其转换为表达式,才能返回其值 。这也是使用JSON来进行Ajax开发的基本原理之一。
现来说说本节的重点,就是在应用eval时,动态脚本所生成的变量都局部的,但很多时候我们可能在调用eval函数的外面使用生成的变量,eval不可能在全局空间内执行,这就给开发带来了不少问题,这该如何作?请看继续往下看吧。
我们先来证实一下eval产生的变量是局部性的,在调用eval函数外是不能访问到此变量的。
var str='全局';//定义一个全局变量 function test(){ eval('var str="局部"'); alert(str);//局部 } test(); alert(str); //弹出:全局
另外,eval生成的函数也是局部的,它只能在生成它的函数内使用,出函数域就不能调用的到。
解决办法:
function gloablEval(code){ if(window.attachEvent && !window.opera){ //ie execScript(code); }else{ //not ie window对象不能省,否则生成的变量在执行的函数外不可见 window.eval(code); alert(str);//局部 //eval(code); //alert(str);//局部 } } var str='全局';//定义一个全局变量 gloablEval('var str="局部"'); alert(str); //弹出:局部,这里用局部的履盖了全局变量的值
现解释一下:
1、对于IE浏览器,默认已经提供了这样的函数:execScript,用于在全局空间执行代码。
2、对于Firefox浏览器,直接调用eval函数,则在调用者的空间执行;如果调用window.eval则在全局空间执行。
JavaScript中的JSON
我们知道,可以使用eval()方法调用JavaScript的编译器把JSON文本转变成对象。因为JSON是JavaScript的一个确切的子集,编译器可以正确地解析JSON文本,然后生成一个对象结构。
var myObject = eval('(' + myJSONtext + ')');
eval函数非常快速。它可以编译执行任何JavaScript程序,因此产生了安全性问题。当使用可信任与完善的源代码时才可以使用eval函数。这样可以更安全的使用JSON解析器。使用XMLHttpRequest的web应用,页面之间的通讯只允许同源,因此是可以信任的。但这却不是完善的。如果服务器没有严谨的JSON编码,或者没有严格的输入验证,那么可能传送包括危险脚本的无效JSON文本。eval函数将执行恶意的脚本。
如果关心安全的话,使用JSON解析器可以防止此类事件。JSON解析器只能辨识JSON文本,拒绝所有脚本,因此它比较安全,JSON官方网站提供的一个开源的JSON解析器和字符串转换器(http://www.json.org/json.js )。
var myObject = myJSONtext.parseJSON();
而JSON的字符串转换器(stringifier)则作相反的工作,它将JavaScript数据结构转换为JSON文本。JSON是不支持循环数据结构的,所以注意不能把循环的结构交给字符串转换器。
var myJSONText = myObject.toJSONString();
Java中的JSON
Java中的JSON解释器官方提供了好几种,我们这里使用的是org.json 包,关于如何使用,请参见另一篇《JSON之org.json包测试》 ,它是基于官方包提供的测试改写而来的。
开始实战
本实例实现了客户端与服务器端通过JSON进行参数的传递与接收,而不是通过原来的XML方式进行通信。页面采用了Prototype的Ajax方式进行异步通信,并采用了官方json.js 进行对象与JSON串的灵活互转。服务器端采用了官方提供org.json 包进行JSON串与Java对象的互转。具体的细节请看代码注释。
客户端实现:
页面展示结果:
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. |
服务器端实现:
{"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 |