[轉貼] JSON之教學筆記

2018070810:28

出處:http://blog.kkbruce.net/2011/01/json.html#.UpVg95Z0O84

就最近寫了很多Ajax的東西,接觸到Ajax的第一件事就是HttpXML.send()之後,伺服器要回傳什麼資料,一般都是responseText或responseXML,也就是說,1. 回傳純文字;2. 回傳XML,純文字難以分析處理(要跑DOM時),XML在伺服器端要花很多力氣去「組合」出XML資料,然後用戶端再寫很多Code去分析處理,這是很沒效率的。

所以就快快把JSON學一學吧!
 

JSON概念


進入JSON前,請先看我這篇「第二篇:簡單介紹JavaScript內建物件」Array物件第一段「Array宣告」的地方,宣告一個Javascript Array物件,基本上是兩種語法:
 
1 // 正式宣告
2 var team1 = new Array('Bruce''Sherry''Happy');
3 // 整合宣告
4 var team2 = ['Bruce''Sherry''Happy'];
5 alert(team1[0]); // Bruce
6 alert(team2[2]); // Happy

一個比較正式,一個是比較簡寫,通常Javascript寫久了,會採用第二種方式來宣告Array。

再來看Javascript物件的宣告,基本上也是兩種:
 
01 // 正式宣告
02 var Bruce = new Object();
03 Bruce.name = 'King Kong';
04 Bruce.age = 18;
05 Bruce.sex = 'male';
06 alert(Bruce.age); // 18
07  
08 // 整合宣告
09 var Bruce = {
10   'name' 'King Kong',
11   'age' : 18,
12   'sex' 'male'
13 }
14 alert(Bruce.name); // King Kong
15 alert(Bruce[name]); // King Kong

一樣,久了也是會選第二種來寫,再來我們看看Javascript的「Array + Object」的宣告:
 
01 // 宣告一個familys Array,裡面包含兩個Object
02 var familys = [
03   {'name' 'Bruce',
04    'age' : 18,
05    'sex' 'male'},
06   {'name' 'Sherry',
07    'age' : 16,
08    'sex' 'famale'}
09 ];
10 alert(family[0].name); // Bruce
11 alert(family[1].sex);  // famale

到這裡你已經會了JSON的80%以上了,JSON (JavaScript Object Notation)已經說明的很清楚了,它是一個JavaScript的子集,它利用Object與Array來表示資料,讓資料很容易的可以交換使用。
 

JSON寫法


我們先來看完整的JSON寫法:
 
01 {
02   'familys' = [
03     {'name' 'Bruce',
04      'age' : 18,
05      'sex' 'male'},
06     {'name' 'Sherry',
07      'age' : 16,
08      'sex' 'famale'}
09   ]
10 }

JSON會建構出兩種結構:(1)「"名稱" : 值」的集合;(2)Array。

JSON的細節

比對上面範例,你會發現一點也不難。

JSON Object:
  1. 以"{"開始,以"}"結尾
  2. 每個名稱後跟著一個":"
  3. 每對"名稱:值"之間用","分隔
 
1 // 以"{"開始
2   'name' 'Bruce',  // 每個名稱後跟著一個":"
3   'age' : 18,        // 每對"名稱:值"之間用","分隔
4   'sex' 'male'
5 // 以"}"結尾

JSON Array:
  1. 以"["開始,以"]"結尾
  2. 值之間使用","
 
01 {
02   // familys為一維陣列,陣列裡包含兩筆物件資料
03   'familys' = [  // 以"["開始
04     {'name' 'Bruce',
05      'age' : 18,
06      'sex' 'male'},  // 值之間使用","
07     {'name' 'Sherry',
08      'age' : 16,
09      'sex' 'famale'}
10   // 以"]"結尾
11 }

JSON Value:
  • 值本身可以是String、Number、true、false、null、ObjectArray

JSON String:
  • 由雙引號包圍的任意Unicode字元集合。可以使用"反斜線(\)"來轉義。
 
1 {
2   "details" "這是JSON的值. \n 此格式比XML合適Ajax交換資料使用."
3 }

JSON Number:
  • 與一般數值相同,除8 / 16進制外。
 

JSON的使用

那JSON要如何使用呢?

原生的JSON格式資料,目前在IE7以上及MF 3以上,已經內建解析JSON格式的能力,但在相容性及網路上的不確定性(其他瀏覽器),建議在有需要使用JSON格式的頁面引用json2.js,依官方說法,請不要在使用json.js這個版本的Script了。

我們有一JSON格式的String:
 
1 var jsonData = "{'familys'=[{'name' 'Bruce''age' : 18, 'sex' 'male'},
2                             {'name' 'Sherry','age' : 16, 'sex' 'famale'}]}"

方法一:使用eval()
這個方法會引發安全性問題,我就不介紹了。

方法二:使用json2.js (IE7以上及MF 3以上可以不引用)

先在網頁中引用json2.js,然後使用json2所提供的parse方法: 
 
1 var jsonData = "{'familys'=[{'name' 'Bruce''age' : 18, 'sex' 'male'},
2                             {'name' 'Sherry','age' : 16, 'sex' 'famale'}]}"
3  
4 var jsonObj = JSON.parse(jsonData);  // 將JSON格式資料轉為物件
5  
6 alert(jsonObj.familys[0].name); // Bruce
7 alert(jsonObj.familys[1].age); // 16

這樣之後,我們就能在Ajax函式將伺服器傳回的JSON格式做解析:
 
1 // ...
2 if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
3   var jsonObj = JSON.parse(xmlHttp.responseText);
4 // ...
5 }

使用了JSON來交換資料後,你會發現相關Ajax的程式碼變簡單了,例如:
 
01 // 原始Ajax函數
02 function Do(xmlHttp) {
03   if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
04     var familys = xmlHttp.responseXML.getElementsByTagName('familys');
05     for (var i = 0; i < familys.length; i++) {
06       var name = familys.getElementsByTagName('name')[0].firstChild.nodeValue;
07       var age = familys.getElementsByTagName('age')[0].firstChild.nodeValue;
08       var sex = familys.getElementsByTagName('sex')[0].firstChild.nodeValue;
09     }
10   }
11 }
12  
13 // 使用JSON後的Ajax函數
14 function Do(xmlHttp) {
15   if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
16     var jsonObj = JSON.parse(xmlHttp.responseText);
17     var name = jsonObj.familys[0].name;
18     var age = jsonObj.familys[0].age;
19     var sex = jsonObj.familys[0].sex;
20   }
21 }

不只有變簡單,而且程式的撰寫更直覺。另外,你也可以把Object轉為JSON:
 
01 // 宣告一個familys Array,裡面包含兩個Object
02 var familys = [
03   {'name' 'Bruce',
04    'age' : 18,
05    'sex' 'male'},
06   {'name' 'Sherry',
07    'age' : 16,
08    'sex' 'famale'}
09 ];
10  
11 var jsonData = JSON.stringify(familys);

更快速的是使用jQuery的$getJSON,但這超出了JSON的討論了。以上是接收解析JSON,那如果我要傳送JSON給伺服器呢?也簡單:
 
1 var xhr = request();  // 建立XHR物件
2 xhr.onreadystatechange = handler;
3 xhr.open('POST',URL);
4 xhr.setRequestHeader('Content-Type''application/json');  // 這裡是重點
5 xhr.send(json);

記得使用'application/json'來傳送即可,但一般伺服器端是看不懂JSON,不過沒關係,在JSON官網最下方或上網找一下,已經有很多高手分享出來可以在伺服器解析JSON的元件或Source Code,讓JSON資料傳送到伺服器後,依然方便好用。
 

使用JSONP進行跨站請求

這個主題比較生硬,如果你不會使用到跨網站請求,可以先跳過。

一般而言,在網站中是不太充許你去存取其他網站的內容,但不是百分百,例如iframe或img就是很好的例子,但其他HTML、Javascript就都不太能做這種事,例如XMLHttpRequest,這是一種保護。但現今網頁已經很少能不去存取其他網站,例如掛個「噗浪」「fb」…,但偏偏XMLHttpRequest不充許跨網站去存取。

後來有人發展出了JSONP(JSON with Padding),JSONP利用Javascript的callback機制,繞過Browser的安全限制,關鍵在動態載入<script src="...">,利用src來載入外部JSON資料或Javascript function到網頁中。

我們先來看動態建立Script
 
1 var Script = document.createElement('script');
2 Script.type = 'text/javascript';
3 Script.src = 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.min.js';
4 document.getElementByTagName('head').[0].appendChild(Script);

這相當於在head最下面新增一段script tag:
 
1 <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.min.js"></script>

這差不多就是JSONP的基礎了,透過動態建立script及Javascript callback,來載入跨網站JSON資料。

最後我們來看整個JSONP的運作流程示意程式碼,注意程式的流程,Step 1在Client--> Step 2在Server--> Step 3 回到Client。

Client端:*.html
 
01 // 使用jQuery
02  
03 // Step 1:送出JSONP請求,
04 $(function(){
05   $('#send').click(function(){
06     // 最後必須是 &callback=funcion 或 &jsoncallback=function 結尾
07     var URL = "http://abc.com/jsonp.aspx?id=1&name=Bruce&jsoncallback=dosomething";
08  
09     $.ajax({
10       type : 'GET',
11       dataType : 'jsonp',  // 記得是jsonp
12       url : URL,
13       error : function(xhr, error){ alert('Ajax request error.');}
14     })
15   })
16 });
17  
18 // Step 3:收到伺服器回應後(response.write(jsonp)),執行的callback的function
19  
20 function dosomething(jsonData){
21   // jsonData會取得Server傳回{...json data ...}
22   alert(jsonData.name);
23   alert(jsonData.age);
24   alert(jsonData.sex);
25 }

在建立非同請求時,在網址最後加上「&callback=函數名稱」或「&jsoncallback=函數名稱」,就可以取得其他網域的資料並執行後續callback的函數。

Server端 *.aspx
01 ' Step 2:進行相關處理
02  
03 '接收到的id & name處理...
04  
05 ' 以下是重點,組合出function及json資料,然後回傳
06 Dim jsonp AS String 
07 ' dosomething是 function name
08 ' {...} 是json data
09 jsonp = "dosomething({ _
10   ' ... json data ... _
11 })"
12  
13 Response.Write(jsonp)

Reference: