JSON与"AJAX"

原来JSON是一种用基于文本的数据描述格式,全称“JavaScript Object Notiation”,类似于XML和SOAP,同样具有跨平台的特性。JavaScript Object Notation (JSON) 是一种轻量级、基于文本、语言无关的数据交换格式。它是从ECMAScript语言标准衍生而来的。JSON为轻便的表示结构化数据,定义了一小套格式化规则.文章于2007年56月26日 发布在http://www.12px.net

JavaScript Object Notation (JSON) 是一种轻量级、基于文本、语言无关的数据交换格式。它是从ECMAScript语言标准衍生而来的。JSON为轻便的表示结构化数据,定义了一小套格式化规则.
1. 说明
JSON是结构化数据串行化的文本格式。它衍生自Javascript的对象实字,这定义在ECMAScript语言标准第三版中。JSON能够描述四种简单的类型(字符串、数字、布尔值及null)和两种结构化类型(对象及数组)。字符串(string)是零个或多个Unicode字符的序列。对象(object)是无次序的零个或多个名/值(name/value)对的集合,这里的name是string类型,value则可以是string、number、boolean、null、object或array类型。数组(array)是零个或多个value的有序序列。"object"和"array"这两个术语来自JavaScript规范。JSON的设计目标是使它成为小的、轻便的、文本的,而且是JavaScript的一个子集。
1.1. 本文档使用的术语/约定
本文档中的关键字:"MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT", "SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY"和"OPTIONAL",按照[RFC2119]中所描述的来解释。本文档中的语法规则按照[RFC4234]中所描述的来解释。
2. JSON语法
JSON文本是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个实字名。JSON文本一个串行化的对象或数组。
JSON-text = object / array
以下是六个构造字符:
begin-array = ws %x5B ws ; [ 左方括号
begin-object = ws %x7B ws ; { 左大括号
end-array = ws %x5D ws ; ] 右方括号
end-object = ws %x7D ws ; } 右大括号
name-separator = ws %x3A ws ; : 冒号
value-separator = ws %x2C ws ; , 逗号
在这六个构造字符的前或后允许存在无意义的空白符。

ws = *( %x20 / ; 空格符 %x09 / ; 水平制表符 %x0A / ; 换行符 %x0D ; 回车符 )
2.1. 值
JSON必须(MUST)是一个对象、数组、数字或字符串,或者是下面三个实字名之一:
false null true
实字名必须(MUST)是小写的,且不允许有其它的实字名。

value = false / null / true / object / array / number / string false = %x66.61.6c.73.65 ; falsenull = %x6e.75.6c.6c ; nulltrue = %x74.72.75.65 ; true
2.2. 对象
对象结构被表示为:一对大括号包围着零个或多个name/value对(或者是成员) 。名是string类型的。每个名后面根一个冒号,把名与值分开。逗号则隔开紧跟在值后的另一个名。对象中的这些名应该(SHOULD)是唯一的。

object = begin-object [ member *( value-separator member ) ] end-object
member = string name-separator value
2.3. 数组
数组结构表示为:方括号包围着零个或多个值(或是元素)。元素间以逗号相隔。
array = begin-array [ value *( value-separator value ) ] end-array
2.4. 数字
数字的表示法与其它多数编程语言相似。一个数字包括一个可能带着负号的整数成分,它后面可能跟着一个小数部分或是指数部分。不允许有八进制及十六进制形式。前面带有0也是被禁止的。小数部分是一个小数点后跟着一个或多个阿拉伯数字。指数部分以大写或小写的E开头,E后面可以跟一个正/负号。接着是一个或多个阿拉伯数字。数字值不能表示成阿拉伯数字数字的序列(如Infinity和Nan是不允许的)。
number = [ minus ] int [ frac ] [ exp ] decimal-point = %x2E ; .digit1-9 = %x31-39 ; 1-9e = %x65 / %x45 ; e Eexp = e [ minus / plus ] 1*DIGITfrac = decimal-point 1*DIGITint = zero / ( digit1-9 *DIGIT )minus = %x2D ; -plus = %x2B ; +zero = %x30 ; 0
2.5. 字符串
字符串的表示法与C语言家族的规范类似。string以引号开始与结束。所有的Unicode字符都可以放置在引号中,除了转义字符:引号、反斜杆\、控制符(U+0000 - U+001F)。所有的这些字符都因该避免。如果字符在基本的多语言环境中(U+0000 - U+FFFF),它可以以这样的六字符序列表示:一个反斜杆,后面跟一个字母U,再跟四个字符代号的十六进制编码的阿拉伯数字。A - F这些十六进制字母可以小写。所以像只包含一个反斜杆的字符可以表示成:"\u005C"。另一种办法,可以用两个转义字符序列来表示一些常用的字符。所以像只包含一个反斜杆字符的字符串可以更简洁的表示成"\\"。转义一个在多语言环境中不存在的字符,这个字符可以表示成一个12字符的序列,编码为UTF-16的代用对(UTF-16 surrogate pair)。所以像只包含一个G音谱字符的字符串可以表示为"\uD834\uDD1E"。
string = quotation-mark *char quotation-mark char = unescaped / escape ( %x22 / ; " quotation mark U+0022 %x5C / ; \ reverse solidus U+005C %x2F / ; / solidus U+002F %x62 / ; b backspace U+0008 %x66 / ; f form feed U+000C %x6E / ; n line feed U+000A %x72 / ; r carriage return U+000D %x74 / ; t tab U+0009 %x75 4HEXDIG ) ; uXXXX U+XXXX escape = %x5C ; \ quotation-mark = %x22 ; " unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
3. 编码
JSON文SHALL被编码为Unicode。缺省的编码为UTF-8。因为JSON文本的开头两个字符总是ASCII字符[RFC0020],我们可以通过查看前面4个字符的0部分,来判断8字节的流是UTF-8还是UTF-16(BE or LE),或者是UTF-32(BE or LE)。
00 00 00 xx UTF-32BE 00 xx 00 xx UTF-16BE xx 00 00 00 UTF-32LE xx 00 xx 00 UTF-16LE xx xx xx xx UTF-8
4. 解析器
JSON解析器将JSON文本转换成其它的表现形式。它必须(MUST)能够接受符合JSON语法的所有文本。解析器也可以(MAY)接受非JSON的形式或一些扩展。实现中,可以设置限制它所接受的文本大小,可以限制JSON文本的最大深度,可以设置数的范围,也可以限制字符串中的字符长度。
5. 生成器
JSON生成器生成JSON文本。目标文本必须(MSUT)严格遵守JSON的语法。
6. IANA Considerations
JSON文本的MIME类型是application/json。类型名:application图表类型名:JSON必需的参数:n/a可选的参数:n/a编码选择: 8bit if UTF-8; binary if UTF-16 or UTF-32
JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
安全考虑:
脚本语言通常都有安全问题。JSON是JavaScript的子集,但是它是一个撤消了附值与调用的安全子集。
JSON文本可以安全的传递个JavaScript的eval()函数。如果字符没有被装入JSON标记符中的标记中,这可以通过JavaScript的两个正则表达式,使用test和replace方法,来快速的判定。
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');

互用性考虑: n/a
发布的规范: RFC 4627
使用该媒体类型的应用程序:

JSON has been used to exchange data between applications written in all of these programming languages: ActionScript, C, C#, ColdFusion, Common Lisp, E, Erlang, Java, JavaScript, Lua, Objective CAML, Perl, PHP, Python, Rebol, Ruby, and Scheme.
其它额外信息(略)
7. Security Considerations
参考第六节中的Security Considerations。

8. 例子
一个JSON对象:
{ "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] } }
该对象的Image成员是一个对象,而Image的Thumbnail成员也是一个对象,且Image的IDs成员是一个数组。下面是一个包含两个对象JSON数组:
[ { "precision": "zip", "Latitude": 37.7668, "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", "Zip": "94107", "Country": "US" }, { "precision": "zip", "Latitude": 37.371991, "Longitude": -122.026020, "Address": "", "City": "SUNNYVALE", "State": "CA", "Zip": "94085", "Country": "US" } ] 
 

先看看用Xml描述论坛中的帖子:

<posts>
<post>
<id>1</id>
<title>帖子1</title>
<content>内容</content>
<posterId>13</posterId>
</post>
<post>
<id>2</id>
<title>帖子2</title>
<content>内容</content>
<posterId>13</posterId>
</post>
</posts>

使用JSON:

{posts:[
{
id:1,
title:"帖子1",
content:"内容",
posterId:13
},
{
id:2,
title:"帖子2",
content:"内容",
posterId:13
}
]};

 下面开始介绍json在ajax中的应用。

一、 引言

  毫无疑问,AJAX已经成为当今Web开发中一种强有力的用户交互技术,但是它的许多可能性应用仍然鲜为人知。在本文中,我们将来共同探讨如何使用JavaScript对象标志(JSON)和JSON分析器在服务器和客户端AJAX引擎之间创建复杂而强有力的JSON数据传输层。我们将详细讨论如何创建一组对象(在其它语言中经常被当作一个包),如何把这些对象串行化为JSON以发送到服务器端,以及如何把服务器端JSON反串行化为客户端JavaScript对象。

  提示:你可以在Douglas Crockford的网站上找到本文中使用的JSON分析器。

  在继续阅读前,本文假定你已经掌握了JavaScript技术并且了解如何创建一个基本的AJAX引擎,并经由AJAX技术向服务器端发出请求和从服务器端接收响应。为了更好地理解本文中示例,你需要下载本文相应的源码文件。

  二、 开始

  为了进一步抽象我们的AJAX请求并有助于我们以后在不同的应用程序间共享AJAX引擎代码,本文使用了一个我自己创建的AJAX引擎。为了使用这个引擎,我们简单地导入三个JavaScript文件并且向一个名为AjaxUpdater的对象发出请求。然后,由该引擎来负责处理其它任务,包括把响应代理到在该请求中指定的回调方法中。下面的示例展示了我们如何使用这个引擎发出请求以及导入相关的文件:

以下是引用片段:
<script type="text/javascript"src="javascript/model/Ajax.js"></script>
<script type="text/javascript" src="javascript/model/HTTP.js"></script>
<script type="text/javascript" src="javascript/model/AjaxUpdater.js"></script>
<script type="text/javascript">
document.load = AjaxUpdater.Update(’GET’, URL, callback);
</script>


  首先,让我们来讨论JavaScript对象。

三、 JavaScript对象


  JavaScript以前经常被误解,似乎它主要用于实现客户浏览器端图形效果。其实,JavaScript是一种强有力的语言,特别当它与AJAX以及一个应用程序的服务器端相结合时;但是,即使在客户端,JavaScript也能够实现远比你预料得多的多的功能。面向对象的JavaScript就是一个示例,它能够使我们创建对象,扩展内在对象,甚至能够把我们的对象创建成包以达到更容易的管理之目的。

  在本文示例中,我们将创建三个对象:Auto,Car和Wheel。其中,每一个都是简单的对象;在此,我们仅使用它们来展示如何创建一个基本包。

  首先,Auto对象被声明为一个新的对象:

以下是引用片段:
  var Auto = new Object();


  注意,这个Auto对象将用作Car对象的父类。因此,Car对象将成为Auto对象的一个属性,只不过它被分离到另一个文件中以更易于管理(这个概念经常被用于其它面向对象的语言中,但是在JavaScript中却并不经常提起它)。下面是这个Car对象相应的代码:

以下是引用片段:
  Auto.Car = new Object();
  Auto.Car.color = "#fff";
  Auto.Car.setColor = function(_color)
  {
  Auto.Car.color = _color;
  }
  Auto.Car.setColor("#333");


  如你所见,该Car对象是Auto对象的一个子对象—这分明是一种类对象层次结构。这个对象有一个名为color的属性和一个用于设置它的方法。在此,我们把color属性设置为灰色以覆盖掉缺省的白色。当在后面我们串行化该对象时请牢记住这个事实。

  下一个对象,Wheel,是Car的一个子对象:

以下是引用片段:
Auto.Car.Wheel = new Object();
Auto.Car.Wheel.color = "#000";


  在此,Wheel是一个基本对象,但是它展示了对象层次中的又一个层。这个对象有一个称为color的缺省值为黑色(“#000”)的属性。

  下面,让我们来分析一下为什么这些对象如此重要以及我们是如何使用它们提供的简单的属性的。

 借助于JSON分析器,我们可以很容易地把刚才创建的JavaScript对象串行化为JSON。首先,我们需要下载该分析器的一个副本,并且要把它添加到文档中。下面是我在本文示例中用于导入该脚本的相应的代码:

以下是引用片段:
<script type="text/javascript" src="javascript/utils/jsonparser.js"></script>


  我已经把该分析器添加到我的javascript目录,即一个称为utils的子目录下。

  下面是最终的包括到其中用于导入适当的JavaScript文件的代码片断:

以下是引用片段:
<script type="text/javascript" src="javascript/Auto.js"></script>
<script type="text/javascript" src="javascript/Car.js"></script>
<script type="text/javascript" src="javascript/Wheel.js"></script>
<script type="text/javascript" src="javascript/utils/jsonparser.js"></script>
<script type="text/javascript" src="javascript/model/Ajax.js"></script>
<script type="text/javascript" src="javascript/model/HTTP.js"></script>
<script type="text/javascript" src="javascript/model/AjaxUpdater.js"></script>


  在导入适当的文件后,我们可以通过把两个div元素和一个onload事件简单地添加到HTML文档中开始串行化。这两个div元素将分别拥有ID:body和loading。其中,这个loading标签将由AJAX引擎使用来指示进度情况,而body标签将用于显示消息。

以下是引用片段:
<div id="loading"></div>
<div id="body"></div>



  onload事件相应于body元素并且设置它的innerHTML属性为JavaScript对象(作为一个串行化的JSON字符串)。为了实现这一目的,我在Auto对象上使用了jsonparser.js文件内的toJSONString方法:

以下是引用片段:
<body onload="document.getElementById(’body’).innerHTML = ’<b>Local objects serialized as JSON</b>
Auto Object: ’+ Auto.toJSONString();">


  这段代码使用了Auto对象及其所有的子对象,并且使用JSON分析器的toJSONString方法把它们串行化为一个JSON字符串。然后,该数据可以被用作服务器端的一种数据交换格式。

  你可能还记得,在前面我们曾调用了一个称为setColor的方法来改变Car对象的颜色。当时,我使用它是因为我想向你展示串行化能够在运行时刻的任何点上实现,而且还为了反映出对象中最新的数据。

  如果你仔细分析一下onload事件,你会注意到,Car和Wheel对象都包装在方括号内,这些方括号代表了父对象(即Auto)。这意味着,该串行化的JavaScript对象能够在运行时刻被发送到服务器端以存储最新的数据,并且也可以在应用程序启动时从服务器端进行接收以便从数据库中检索多数的当前数据。最精彩的部分在于,为了创建一种“无缝”的过程,所有与服务器之间实现的数据交换都可以使用JSON技术来实现。

  下面,让我们来看一下相同的数据是如何从服务器端接收的,以及它们是如何被使用最新的数据(典型地,来源于一个数据库)串行化为客户端JavaScript对象的。

五、 把JSON反串行化为客户端JavaScript对象


  在本文中,我简单地把一个静态文件创建为JSON响应,但是在实际开发中,你可以把这些数据存储在一个数据库中并且使用一种服务器端语言返回它。基于这一能力,我们就可以轻松地创建一种强有力的数据交换过程!在前面,我们已经分析了这一串行化过程。凭基本的AJAX体验,你应该能够理解数据是如何被寄送到服务器端的。现在,让我们着手讨论反串行化的问题。首先来看一个针对本文示例提供的静态JSON文件。这个文件其实是我们在上一节中串行化的数据:

以下是引用片段:
{"Car":{"color":"#333","Wheel":{"color":"#000"}}}


  作为一个请求JSON文件的示例,当我们点击下列链接时将请求这个串行化的Auto对象:

以下是引用片段:
<a href="javascript:AjaxUpdater.Update(’GET’, ’json/data.js’, displayResponse);">Get remote JSON</a>


  一旦接收到响应消息,我们的称为displayResponse回调方法就会被激活,然后,我们就能够反串行化并开始使用这些对象:

以下是引用片段:
<script type="text/javascript">
function displayResponse()
{
 if(Ajax.checkReadyState(’loading’) == "OK")
 {
  var Auto = Ajax.request.responseText.parseJSON();
  document.getElementById("body").innerHTML += "
<b>Remote JSON unserialized</b>";
  document.getElementById("body").innerHTML += "
Car color: "+Auto.Car.color;
  document.getElementById("body").innerHTML += "
Wheel color: "+Auto.Car.Wheel.color;
 }
}
</script>


  这是相当激动人心的一部分!一旦我们拥有了该responseText,我们就能够简单地使用JSON分析器中的parseJSON方法来从串行化的数据中重建我们的Auto对象。借助于这个新的Auto对象,我们就可以调用相应的子对象。这个特征允许我们在服务器和客户端来回发送对象—而不必进行大量的分析工作,然而在以前标准的XML响应情况下我们将却必须这样做。这样以来,我们就可以创建出能够基于AJAX技术来保留自身状态的客户端JavaScript对象。

相关文章