一、引言
当微软把ActiveX XMLHTTP对象纳入到JavaScript的Internet Explorer实现中时,它实际上已经为Web应用程序的又一次革命(异步JavaScript+XML,简称AJAX)埋下了“火种”。今天,Firefox,Safari,Opera及其它浏览器都支持XMLHttpRequest对象,正是这些支持最终才导致了诸如colr.org,backpackit.com和maps.google.com等著名网站的产生。尽管这些网站(不止这些)所提供的应用程序运行于一种浏览器中,但是它们在行为和外观上却极类似于传统的桌面应用程序。
在AJAX技术中,在用户观看并与页面交互的同时(这正相应于AJAX中的“异步”部分),由页面中的JavaScript负责把数据请求发送到一个Web服务器。这些请求只是一些普通的HTTP请求,与浏览器用于页面(连同其中的任何图像,层叠式样表等内容)检索的HTTP完全相同。同时,XMLHttpRequest对象可以用于检索任何类型的数据,而不仅仅是XML类型。例如,JavaScript可以使用XMLHttpRequest来检索一个来自于Web服务器的普通文本文本并且把它的内容显示于一个表单中。
通过查找位于数据之前的“content-type”头部,XMLHttpRequest对象分析从Web服务器返回的数据的MIME类型。例如,如果这些数据的MIME类型是“text/plain”,那么你可以通过分析XMLHttpRequest对象的responseText属性来存取它;然而,如果其MIME类型为“text/xml”,那么XMLHttpRequest对象必须采取额外的措施:它要在返回的文档对象上运行一个XML分析器并在内存中构建一棵文档对象模型(DOM)树来描述该文档,并且还要使其可用于responseXML属性。然后,你才可以使用JavaScript的标准DOM方法在树中导航并检索元素、属性及位于该DOM树中的其它文本。
虽然XML是进行数据交换的标准方式,但是通常它不是最好的方式。尽管XML可以把结构和元数据添加到数据上,但是它使用了一种相当繁琐的方式。XML还有一种相对复杂的语法,因而需要一种分析器对之进行专门分析。在JavaScript中,XML必须被分析成一棵以备后用的DOM树。并且,一旦你构建了这棵DOM树,你还必须在其中导航以便创建相应的JavaScript对象或者以其它方式在你的客户端Web应用程序中使用XML数据。
幸好,你还有另外更好的可选方案。
二、JSON简介
JavaScript对象标志,简称JSON,是一种描述数据的轻量级语法。JSON的优越性基于这样的事实:它本身就是JavaScript语言的一个子集。你会在后面看到这种特征的重要性。首先,让我们比较一下JSON和XML的原始语法。
XML和JSON都使用结构化方法来标记数据。例如,一个地址簿应用程序可能提供一个Web服务—它将以XML形式生成如下的地址卡片:
xml代码
<?
xml version='1.0' encoding='UTF-8'
?>
<
card
><
fullname
>
Sean Kelly
</
fullname
><
org
>
SK Consulting
</
org
><
emailaddrs
><
address
type
='work'>kelly@seankelly.biz</address><address
type
='home'
pref
='1'>kelly@seankelly.tv</address></emailaddrs><telephones><tel
type
='work'
pref
='1'>+1
214 555 1212</tel
><
tel
type
='fax'>+1
214 555 1213</tel
><
tel
type
='mobile'>+1
214 555 1214</tel
></
telephones
><
addresses
><
address
type
='work'
format
='us'>1234
Main StSpringfield, TX 78080-1216</address
><
address
type
='home'
format
='us'>5678
Main StSpringfield, TX 78080-1316</address
></
addresses
><
urls
><
address
type
='work'>http://seankelly.biz/</address><address
type
='home'>http://seankelly.tv/</address></urls></card>
而使用JSON来表达,上面的形式将变成如下模样:
"fullname": "Sean Kelly","org": "SK Consulting","emailaddrs": [{"type": "work", "value": kelly@seankelly.biz"},{"type": "home", "pref": 1, "value": "kelly@seankelly.tv"}],"telephones": [{"type": "work", "pref": 1, "value": "+1 214 555 1212"},{"type": "fax", "value": "+1 214 555 1213"},{"type": "mobile", "value": "+1 214 555 1214"}],"addresses": [{"type": "work", "format": "us","value": "1234 Main StnSpringfield, TX 78080-1216"},{"type": "home", "format": "us","value": "5678 Main StnSpringfield, TX 78080-1316"}],"urls": [{"type": "work", "value": "http://seankelly.biz/"},{"type": "home", "value": "http://seankelly.tv/"}]} 正如你所见,JSON也提供了一种具有嵌套数据元素的结构,就象XML一样。与XML一样,JSON也是基于文本的,且它们都使用Unicode编码,且其与XML一样具有可读性。主观上来看,JSON更为清晰且冗余更少些。JSON网站提供了对JSON语法的严格描述,只是描述较简短。从总体来看,XML比较适合于标记文档,而JSON却更适于进行数据交换处理。一个JSON文档的每一个实例都负责描述一个对象—具体的描述是通过使用嵌套的对象,数组,字符串,数字,布尔值或null值来实现的。
上面地址卡例子的JSON版本更为小些,仅占用大约682字节的空间,而XML版本需要744字节空间。当然,这不是什么惊人的节省。其实,JSON的真正优点在于数据分析方面。
三、JSON与XML数据分析对比
借助于XMLHttpRequest对象,你可以从自己的基于AJAX的应用程序内部检索XML和JSON文件。典型情况下,你可以使用类似如下的交互:
var req = new XMLHttpRequest();req.open("GET","http://localhost/addr?cardID=32", /*async*/true);req.onreadystatechange = myHandler;req.send(/*no params*/null);
随着对Web服务器的不断响应,被你传递的处理器函数(在本例中是myHandler)被反复调用,这种特征提供给你一种时机—及早地取消事务,更新一个进度条,等等。通常,你只是在Web请求完成时才采取行动(应用返回的数据)。
为了处理上面地址卡程序的XML版本,myHandler的编码可以类似如下:
function myHandler() {
if (req.readyState == 4 /*完成*/) {//用第一个街道地址更新表单中的地址域var addrField = document.getElementById('addr');
var root = req.responseXML;
var addrsElem = root.getElementsByTagName('addresses')[0];
var firstAddr = addrsElem.getElementsByTagName('address')[0];
var addrText = fistAddr.firstChild;
var addrValue = addrText.nodeValue;addrField.value = addrValue;}}注意,你不必自己分析XML文档,分析任务可以由XMLHttpRequest对象为你自动完成。之后,这个XMLHttpRequest对象使得由分析生成的DOM树可应用于responseXML属性中。然后,你可以借助这个responseXML属性并调用getElementsByTagName方法来查找文档中的addresses部分,但仅能使用找到的第一个(其实只有一个)。然后,你再次在找到的address上调用getElementsByTagName方法来查找下一层中的第一个address元素,然后再次使用找到的第一个address……然后,你得到该元素的第一个DOM子结点(它是一个文本结点)并得到该结点的值(它正是你想找的街道地址)。最后,你就可以在表单域中显示它。
显然,这是一项工作量很大的工作!现在,让我们试用一下JSON:
function myHandler() {
if (req.readyState == 4 /*complete*/) {
var addrField = document.getElementById('addr');
var card = eval('(' + req.responseText + ')');
addrField.value = card.addresses[0].value;}} 你需要做的第一件事情是手工地分析JSON响应。然而,因为JSON是JavaScript的一个子集,所以你可以通过调用eval方法使用JavaScript自己的编译器来完成这些。分析JSON是非常简单的!而且,在产生于JSON中的一个对象中导航与在任何JavaScript对象中导航完全一样。这比在DOM树中导航要容易得多。例如:
•card.addresses[0].value对应第一条街道地址:“1234 Main Stb &”;
•card.addresses[0].type对应地址的类型:“work”;
•card.addresses[1]对应一个家庭地址对象;
•card.fullname对应卡片名:“Sean Kelly”。
如果仔细观察,那么你可能注意到,示例程序的XML版本至少要处理包含在文档中的一个对象—根文档元素card。这在JSON版本中是不存在的。为什么?如果你曾开发过存取一个Web服务的JavaScript,那么你就会知道你要从Web服务中取回什么。然而,你可以在JSON中包括下面一种更为简练的形式:
{"card": {"fullname": }} 通过使用这一技术,你的JSON文件总是以一个对象开头并且用单个命名的属性来标记该对象的“类型”。
四、JSON的快速可靠性
JSON能够生成更小的文档,且其在JavaScript脚本中更易于使用。XMLHttpRequest能够为你自动分析XML文档,然而你必须手工分析JSON。这样以来,你可能质疑:分析JSON是否比分析XML更慢?对比JSON,我针对上面的地址卡测试了嵌入到XMLHttpRequest中的XML分析器—通过把这些数据置入上千次的循环中。最终结果表明,分析JSON比分析XML快大约10倍!如果想实现AJAX程序的行为类似于桌面应用程序,那么速度就是一切。很明显,JSON是胜者。
当然,你不可能一直控制为你的AJAX应用程序产生数据的服务器端。你可以使用一种第三方服务器来处理你的数据,而且让该服务器仅提供XML输出。然而,如果该服务器中恰巧能够提供JSON支持,那么你能否确定并敢于使用这一支持?
注意,在上面的示例中,你是直接把响应文本传递到一个对eval的调用中。如果你信任并控制了服务器,这是没有问题的;然而,另外一些情况下,一个恶意的服务器有可能给你的浏览器执行带来危险操作。为此,你最好使用一个用JavaScript编写的JSON分析器。幸好,已经存在可用的分析器了。
谈到分析器,Python迷们可能还没有注意到,JSON不仅是JavaScript的一个子集,而且它还是Python的一个子集。你可以直接在Python中使用JSON,或利用一种安全的JSON分析器。现在,针对于JSON的分析器也大量地存在于其它语言中;你可以参考JSON.org网站来选择使用相应的分析器。
五、服务器端技术对JSON的支持
到目前为止,我们一直集中于讨论如何把JSON应用于客户端浏览器上的基于AJAX技术的Web应用程序。当然,Web服务器端必须存在一定的技术支持才能实现首先生成JSON,然后由客户端使用JSON。幸好,基于现有数据结构创建JSON是一件相当直接的事情。另外,一些Web应用程序框架(例如TurboGears)已经自动包括支持JSON输出。
另外,商业Web服务供应商也都特别关注JSON。Yahoo最近在其Web服务中大量地加入对JSON的支持。Yahoo的多种搜索服务,旅行规划者,del.icio.us和高速公路交通服务都支持JSON输出。无疑,其它一些主要的Web服务供应商也都会逐渐地提供对JSON的支持。
六、结论
JSON的基本思想是,把自己实现为JavaScript(和Python)的一个子集,从而使其成为一种轻量级的和高度灵活的处理AJAX数据交换的方式。与传统的XML处理技术相比,这个工具的分析速度更快且更为易用。从该工具的性能和使用现状来看,它有可能会成为下一代Web 2.0开发中XML数据操作的主要替代者。任何开发者,无论是开发标准桌面应用程序还是开发Web应用程序,只要使用XML数据处理,都会欣赏JSON的简易特征。最后,我衷心祝愿JSON能加快你的基于AJAX技术的Web 2.0应用程序的开发。