javascript
《Ext JS权威指南》——1.2节JSON概述
1.2 JSON概述
1.2.1 認識JSON
XML雖好,可作為數據交換格式,有時會喧賓奪主,標記比數據還多,徒增流量。更重要的是,在JavaScript中處理XML實在太不便利了。而JSON,沒有附加的標記,在JavaScript中可作為對象處理,因而漸漸成了目前Web開發的標準數據交互格式。
JSON的英文全稱是“JavaScript Object Notation”,意思就是JavaScript對象表示法。它是一種基于文本的、獨立于語言的輕量級數據交換格式。它來源于ECMA-262第三版定義的JavaScript對象直接量(literal)。它不但易于閱讀和編寫,還易于機器解析和生成,而且完全獨立于語言的文本格式,因而,JSON是一種理想的數據交換語言。
1.2.2 JSON的結構
JSON有對象和數組兩種結構。
對象結構以“{”(大括號)開始,“}”(大括號)結束。中間部分由0個或多個以“,”(逗號)分隔的“關鍵字(key)/值(value)”列表構成,而關鍵字與值之間必須以“:”(冒號)分隔。其結構語法如下:
從上面的結構可以看到,這種結構的JSON有點類似其他語言中的字典或散列表。結構中的關鍵字是字符串,而值可以是字符串、數值、true、false、null、對象或數組。
注意 true、false和null必須全部為小寫字母。當值為對象或數組時,變量記錄的是對象的指針。
數組結構以“[”(中括號)開始,“]”(中括號)結束。中間部分由0個或多個以“,”分隔的值(value)列表構成,其結構語法如下:
值可以是字符串、數值、true、false、null、對象或數組。
注意 如果在最后一個“關鍵字/值”后,“}”之前有1個“,”,如“{a:1,b:2,}”在IE 8及其之前版本的瀏覽器會報錯,而在IE 9或其他瀏覽器則不會報錯。這也是有些程序在Firefox中運行正常,在IE 8及其之前的瀏覽器中不能運行的主要原因。數組結構的JSON也存在這個問題,需要特別注意。
1.2.3 JSON的例子
下面是一個JSON例子:
從上面的例子可以看到,數字“1”也可以作為關鍵字。為什么呢?這是因為在JavaScript中,會自動根據需要將數字轉換為字符串。從“2”、“.”和“中文”中可以看到,基本上,只要是字符串都可以作為關鍵字,不過筆者不建議使用這樣的名稱,因為這會造成對象訪問上的問題,除非你永遠保持使用“對象[關鍵字]”的方式訪問對象,這會在1.2.4節中詳細描述。
在“person”中,其值是一個數組結構的JSON,而該JSON又是由JSON結構的值構成的,這說明,這兩種結構的JSON數據是可以嵌套使用的。而“object”值則表明JSON結構也可以作為值嵌套在JSON結構中。
1.2.4 在JavaScript中使用JSON
因為JSON是JavaScript的一個子集,所以可以在JavaScript中輕松地讀取、修改JSON中的數據并向JSON中添加數據。
在開始學習下面的內容之前,請先準備一個空白頁面,然后在裝有Firebug的Firefox中打開該頁面,最后在Firefox中打開Firebug窗口并在控制臺的命令行中輸入以下代碼:
如果對Firebug還不熟悉,可先閱讀第3章3.1節的內容。以上代碼定義了一個JSON對象并賦值給變量obj。從代碼中可以看到,定義一個JSON對象非常簡單,只要按照數據格式把數據寫在“{}”中就可以了。當然,你也可以定義一個空的JSON對象,代碼如下:
var obj={};以上代碼就定義了一個空的JSON對象,在很多時候會使用到。
在JSON中讀取數據有兩種方法。第一種方法是在“.”(小數點)后加上關鍵字。第二種方法是在中括號中包含關鍵字。下面我們來測試一下這兩種方法。
首先在Firebug中輸入的代碼后面加入以下代碼:
console.log(obj.1)代碼中“obj”是指向JSON對象的變量,“1”是JSON對象關鍵字。“console.log”是Firebug用來在控制臺輸出信息的命令。
單擊“運行”,會看到如圖1-1所示的錯誤信息。
這說明不能通過該方法讀取關鍵字為數字的數據。將代碼中的“1”替換為“2”、“.”,也會出現錯誤信息。
單擊“清除”按鈕清除控制臺的信息后,將名稱修改為“中文”,最后單擊“運行”可看到如圖1-2所示的信息。
這說明中文是可以直接在“.”后使用的。
如果要讀取“person”中第2個對象的“name”,可將“console.log”代碼修改為下面的代碼:
從以上的測試可以了解到,如果要讀取以數字或運算符作為關鍵字的數據,必須使用中括號加關鍵字的方法,因此不是在特殊情況下,不建議使用這樣的關鍵字,而且這樣的名稱不便于閱讀與維護。中文名稱嘛,筆者也不推薦,不過根據自己需要靈活掌握吧。
最后一點要指出的是,在代碼中要保持一致的風格,以便于代碼的維護。
要遍歷JSON對象中的數據,可使用for…in循環。譬如要遍歷上面示例中“obj”的數據,可編碼如下:
代碼中,通過循環可一個個讀取JSON中的關鍵字,并將名稱保存在變量“c”中,然后可使用中括號加關鍵字的方法讀取數據。
在Firebug中運行該循環將看到如圖1-3所示的顯示結果。
要修改JSON對象的數據很簡單,和普通變量賦值沒什么區別。譬如要將示例中“count”的值修改為10,可以執行以下的代碼:
要刪除JSON對象內的屬性,使用delete語句就可以了。例如:
屬性sex已被刪除。
1.2.5 在.NET中使用JSON
當JSON逐漸成為Ajax的標準數據交互格式時,在.NET中處理JSON數據只能使用字符串拼接的方法,十分麻煩,因而催生了JSON.NET這個項目。
JSON.NET是一個免費的開源項目,大家可以登錄http://json.codeplex.com/下載最新版本,本書使用的版本是4.0 release 1,本節的示例將使用該版本進行演示。
JSON.NET的功能有很多,本書主要講述以下兩個Ext JS項目常用的功能:
通過序列化方法將.NET對象轉換為JSON對象。
使用LINQ to JSON讀寫JSON對象。
在JSON.NET壓縮包的bin目錄下有Net、Net20、Net35、Silverlight和WindowsPhone5個目錄,目錄里有對應不同.Net Framework版本的庫文件,根據使用的.Net Framework版本使用對應的庫文件就可以了。譬如本書的例子使用的是.Net Framework 4.0版本,因而將Net35目錄下的Newtonsoft.Json.Net35.dll文件添加到項目的bin目錄就可以了。
要使用序列化功能,需在代碼中加入以下引用代碼:
using Newtonsoft.Json; 如果要使用LINQ to JSON,需在代碼中加入以下引用代碼: using Newtonsoft.Json.Linq;在開發Web應用時,一般都需要將數據庫查詢出的數據轉換為JSON格式文本傳送回客戶端,這就需要進行序列化。在JSON.NET中,要進行序列化,常用的是JsonConvert對象的SerializeObject方法。其基本的語法格式如下:
代碼中“object”就是要序列化的.NET對象。序列化后的返回值是字符串。
下面我們通過一個例子來加深一下認識。例子主要實現的功能是將微軟示例數據庫“Northwnd”中客戶表(Customers)的所有客戶數據以JSON格式返回客戶端,其代碼如下:
代碼中,首先從實體模型中查詢出數據集合“q”,然后將數據集合“q”序列化成JSON格式字符串并賦值給變量“Message”,最后在頁面中輸出。在瀏覽器中打開頁面將看到以下的結果:
[{"CustomerID":"ALFKI","CompanyName":"Alfreds Futterkiste","Country":"Germany","City":"Berlin","Address":"Obere Str. 57","PostalCode":"12209","Phone":"030-0074321","Region":null}, …, {"CustomerID":"WOLZA","CompanyName":"Wolski Zajazd","Country":"Poland","City":"Warszawa","Address":"ul. Filtrowa 68","PostalCode":"01-012","Phone":"(26) 642-7012","Region":null}]從上面的例子可以看到,將查詢數據序列化成JSON文本是一件非常簡單的事。其實,對.NET對象的序列化還有很多方式,囿于篇幅,本書就不一一介紹了,有興趣可以詳細閱讀JSON.NET的文檔。
事實上,Ext JS對數據返回的格式是有一定要求的,并不是簡單地返回序列化后的數據就行,這時就需要用到LINQ to JSON。LINQ to JSON的作用就是根據需要的JSON格式組織文本數據。
LINQ to JSON需要使用到JObject、JArray、JPropery和JValue 4個對象,這4個對象的詳細說明如表1-1所示。
下面我們通過一個例子說明如何使用LINQ to JSON。Ext JS的所需JSON格式數據一般如下:
{"total":5, //記錄總數"rows":[//JSON對象格式的數據列表] } 示例將演示如何根據以上格式返回客戶表數據,代碼如下:public string Message { get; set; }protected void Page_Load(object sender, EventArgs e){NorthwindEntities ne = new NorthwindEntities();var q = ne.Customers.OrderBy(m => m.CompanyName).Select(m => new{m.CustomerID,m.CompanyName,m.ContactName}).ToList();Message = new JObject(new JProperty("total", q.Count()), //創建記錄總數new JProperty("rows", new JArray( //創建數據數組from p in qselect new JObject(new JProperty("id", p.CustomerID),new JProperty("cpname", p.CompanyName),new JProperty("contactName", p.ContactName)) ))).ToString();}從上面的代碼可以看到,構建固定格式的JSON數據是相當直觀的。將粗體代碼與格式數據對比,可以看到,最外層的JObject創建了格式中最外層的“{}”,然后依次使用JProperty生成記錄總數數據和數據列表。而代碼中的JArray的作用就是生成“[]”,將使用LINQ to JSON方式生成的一個個數據對象組合成數組。本來是希望直接通過LINQ to JSON將實體模型轉換成JSON的,但這樣會產生“LINQ to Entities 僅支持無參數構造函數和初始值設定項”的錯誤,因而本示例先將查詢的數據轉換為列表(ToList()),再進行轉換。使用LINQ to JSON可直接在select語句生成JSON數據對象,無須其他轉換過程,相當方便。在使用select語句生成數據對象時,首先使用JObject生成“{}”,然后使用JProperty生成對象的數據。
在瀏覽器中打開頁面,將看到以下的結果:
因為這樣生成的“rows”值是字符串,而不是數組。
有時候,在客戶端以JSON格式將數據提交到服務器比較方便。譬如,直接在Grid修改了不同行和列的數據,最后一次性將修改的數據提交到服務器端處理,這時候,使用JSON格式提交數據會很方便,例如以下提交的數據:
數據表示在Grid中修改了3行數據,第1行修改了標題(title)和作者(author),第2行修改了作者,第3行修改了是否顯示(isShow)。
在服務器端使用JObject或JArray的Parse方法就可輕松地將字符串轉換為JSON對象,然后通過對象的方法提取數據,下面是服務器端的處理代碼:
在代碼中,因為已知數據是使用數組形式提交的,所以采用JArray的Parse方法。
什么?你不知道數據是以數組還是對象形式提交?
這……
數據的提交方式應該是一種雙方的約定,不然要處理未知的數據會很麻煩,所以不用擔心這個問題。
第1層foreach循環用來獲取JObject對象。第2層foreach用來獲取修改過的字段名稱。在這里要注意,數據默認已約定存在id這個字段。
代碼運行后將看到如圖1-4所示結果。
從結果可以看到,數據已經被分拆出來,這樣你就可以根據id和字段去更新數據庫了。
1.2.6 在Java中使用JSON
Gson是谷歌的一個開源項目,其作用是在Java對象和JSON之間實現相互轉換。大家可登錄http://code.google.com/p/google-gson/下載最新版本,本書使用的版本是1.6版,本節的示例都將使用該版本。
Gson的功能很多,這里囿于篇幅就不一一介紹了。本節的重點是講述如何使用Gson生成Ext JS格式的返回數據。
要使用Gson,將gson-1.6.jar文件復制到項目的“lib”目錄就行了。譬如在動態Web項目中使用Gson,將文件復制到“WebContentWEB-INF”下的lib目錄即可。
要引用Gson,需在引用文件中加入以下代碼:
import com.google.gson.*;你也可以根據需要細化引用。
要生成1.2.5節中介紹的JSON格式數據,需要使用JsonObject和JsonArray兩個對象,這兩個對象的詳細說明如表1-2所示。
這兩個對象是如何使用的,請看下面的代碼:
String connectionUrl = "jdbc:sqlserver://192.168.0.254:1433;" +"databaseName=Northwind;;user=sa;password=abcd-1234";Connection con = null; Statement stmt = null; ResultSet rs = null;try { //使用JDBC從數據庫獲取數據Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");con = DriverManager.getConnection(connectionUrl);String SQL = "SELECT CustomerID,CompanyName,ContactName " +"FROM Customers order by CompanyName";stmt = con.createStatement();rs = stmt.executeQuery(SQL);int count = 0; //計算記錄總數//構建數據列表JsonArray array=new JsonArray();while (rs.next()) {//構建每行數據對象JsonObject obj= new JsonObject();obj.addProperty("id", rs.getString("CustomerID"));obj.addProperty("cpname", rs.getString("CompanyName"));obj.addProperty("contactName", rs.getString("ContactName"));array.add(obj);count++;} //構建返回格式數據JsonObject json=new JsonObject();json.addProperty("totals", count);json.add("rows", array); response.getWriter().write(json.toString());rs.close();} catch (Exception e) {response.getWriter().write(e.getMessage()); } finally {if (rs != null) try { rs.close(); } catch(Exception e) {}if (stmt != null) try { stmt.close(); } catch(Exception e) {}if (con != null) try { con.close(); } catch(Exception e) {} }代碼中,注釋“構建數據列表”之前的代碼是實現數據庫查詢數據的,而我們的重點是JSON,所以我們的關注點是注釋下面的代碼。因為Gson不支持LINQ to JSON,所以我們必須一步步地構建JOSN數據。
首先創建一個JsonArray對象,準備在循環中插入數據。在while循環中,每行數據就是一個JsonObject對象,因而要創建新的JsonObject對象,然后使用addProperty方法將每列數據添加到JsonObject對象中,最后是將這個JsonObject對象使用JsonArray的add方法添加到數組中。這樣,要返回的數據列表就構建完成了。
最后一步就是構建最外層的JsonObject對象,這個步驟比較簡單。首先是使用addProperty方法添加記錄總數,然后使用add方法將JsonArray對象作為“rows”的值添加到JsonObject對象中,最后使用toString方法轉換成字符串返回客戶端。在這里要注意JsonObject對象的addProperty方法和add方法的區別,addProperty方法是用來添加原生數據類型的,而add方法是用來添加JsonElement(包括JsonObject、JsonArray、JsonPrimitive和JsonNull)對象的,詳細的說明可閱讀Gson的API。
在Java中要處理1.2.5節中介紹的JSON數據,可使用JsonParser對象的Parse方法,具體代碼如下:
代碼中,首先使用JsonParser對象的Parse方法將字符串轉換為JsonElement對象,然后使用getAsJsonArray方法將其轉換為JsonArray。通過循環從JsonArray中獲取JsonObject對象。因為JsonObject沒有提供獲取關鍵字的方法,所以要將JsonObject對象轉換為Set,再將Set中的數據轉換為Map集合,最后使用getKey方法提取關鍵字。
代碼運行后的結果參見圖1-4。
1.2.7 更多有關JSON的信息
在本書只是簡單地介紹C#和Java這兩種開發語言處理JSON數據的方法,如果讀者需要其他語言有關的JSON的信息,或不喜歡筆者介紹的兩個JSON庫,可登錄http://www.json.org/json-zh.html獲取更多信息。
總結
以上是生活随笔為你收集整理的《Ext JS权威指南》——1.2节JSON概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 交换两个变量的值,不使用第三个变量的四种
- 下一篇: 生活在信息世界,人人都该懂得大数据概念