一、JSON解析與字符串化
JSON.stringify() 序列化對象、數組或原始值
語法:JSON.stringify(o,filter,indent)
o,要轉換成JSON的對象、數組或原始值
filter,指定要序列化的屬性名
indent,格式化為可讀的代碼,可指定分隔符或指定的縮進空格個數
var man = { name: "張三", Age: 24, money: 123123 }; var str1 = JSON.stringify(man); //基本序列化 document.write(str1 + "<br/>"); //{"name":"張三","Age":24,"money":123123} var str2 = JSON.stringify(man, ["name", "Age"]); //指定要序列化的屬性 document.write(str2 + "<br/>"); //{"name":"張三","Age":24} var str3 = JSON.stringify(man,["name","Age","money"],"---"); //指定格式化數值 document.write(str3); //{ ---"name": "張三", ---"Age": 24, ---"money": 123123 }
JSON.parse() 反序列化一個字符串為JSON對象
語法:JSON.parse(s)
JSON.parse(s,reviver)
s,要解析的字符串。reviver,用來轉換解析值的可選函數
var man = { name: "張三", Age: 17, money: 123123 }; var str1 = JSON.stringify(man, ["name", "Age"]); //指定要序列化的屬性 var str2 = JSON.parse(str1); document.write(str2.name + str2.Age + str2.money); //張三24undefined 由於money參數沒有序列化,所以undefined
另外由於JSON.parse存在兼容性問題,IE6,IE7並不支持此函數(目前,搜狗,360瀏覽器也不支持)。所以上網找了兩個兼容性比較好的字符串轉JSON方法,代碼如下:
//第一種:eval方式解析 function strToJson(str){ var json = eval('(' + str + ')'); return json; } //第二種:new Function形式 function strToJson(str){ var json = (new Function("return " + str))(); return json; }
JSON是一種輕量級的數據交換格式,實質上就是一個javascript對象,因此格式與javascript定義的對象一樣。在數據傳輸過程中,JSON是以字符串的格式傳輸的。
特別注意:如果obj本來就是一個JSON對象,那么使用eval()函數轉換后(哪怕是多次轉換)還是JSON對象,但是使用parseJSON()函數處理后會有問題(拋出語法異常)。
到目前為止學會了如果將一個javascript對象轉換為JSON,也知道了如何將JSON反轉換為javascript對象。現在來結合后台程序,練下手。
先來個jQuery獲取后台返回的JSON數據並處理的例子,控制器代碼:
public ActionResult Index() { return View(); } public JsonResult GetJSON() { return Json(new {Id=1,Name="劉備",Age=23},"text/html",JsonRequestBehavior.AllowGet); }
視圖代碼:
<title>JSON示例</title> <script src="/jquery-1.8.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $("#btn1").click(function () { $.ajax({ url: "/Home/GetJSON", type: "post", dataType: "json", success: function (response) { $("#Id").text(response.Id); $("#Name").text(response.Name); $("#Age").text(response.Age); } }) }) }) </script> </head> <body> <div id="imglist"> <ul> <li id="Id"></li> <li id="Name"></li> <li id="Age"></li> </ul> <input type="button" id="btn1" value="確認" /> </div> </body> </html>
此示例實現的效果是,當點擊按鈕時,三個li的值自動設置為需要的內容。
細心的朋友應該注意到,在Result里面返回了一個JsonRequestBehavior.AllowGet。其實這是一個枚舉,在MVC中的JSONResult里面用於控制HTTP Get請求的處理方式,先來了解下這個枚舉。
這是一個簡單枚舉,而且只有兩個選項,以兄弟我一貫的方式,依然用個列表展示出來。
成員 成員值 說明
AllowGet 0 允許來自客戶端的 HTTP GET 請求。
DenyGet 1 不允許來自客戶端的HTTP GET請求。
默認值為 DenyGet。允許 GET 請求可能會導致用戶在某一網站中仍處於已登錄狀態時訪問另一個網站。這可能會生成導致信息泄漏的安全漏洞。(當然這是微軟MSDN里面的話)
其實在本例中,這個選項完全可以刪開,完全沒影響。因為本例的AJAX請求使用的是post方式,但是如果將AJAX的請求設置為get時,如果再不設置該屬性為AllowGet時,那就真的獲取不到數據了。
另外.net還提供了很好用的C#對象轉JSON的類,JavaScriptSerializer類,此類位於System.Web.Script.Serialization命名空間下。如要使用此命名空間,需要引用System.Web.Extensions庫文件。要想了解此類的詳細信息請查看。
本處只給出一個簡單示例。先來看控制器代碼:
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult GetJSON() { Person p = new Person(); p.Id = 1; p.Name = "關羽"; p.Age = 22; JavaScriptSerializer jss = new JavaScriptSerializer(); string JsonStr = jss.Serialize(p); return Content(JsonStr); } } public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
視圖代碼:
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>JSON示例</title> <script src="/jquery-1.8.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $("#btn1").click(function () { $.ajax({ url: "/Home/GetJSON", type: "post", dataType: "html", success: function (response) { var obj = JSON.parse(response); $("#Id").text(obj.Id); $("#Name").text(obj.Name); $("#Age").text(obj.Age); } }) }) }) </script> </head> <body> <div id="imglist"> <ul> <li id="Id"></li> <li id="Name"></li> <li id="Age"></li> </ul> <input type="button" id="btn1" value="確認" /> </div> </body> </html>
只代碼能夠將C#對象中的信息直接在javascript中處理並顯示。只是無論是返回JsonResult還是Content都需要JSON.parse()一下,不像第一個示例那樣不用轉換,不知道是測試出了問題,還是本類就只是這樣子。
2013-4-26 今天終於正式了一個長久以來不注重的問題,就是jQuery AJAX返回的dataType:"json"的問題,因為只要設置了dataType為json,就無法進入到seccess。上網查了一下,統一的說法是,jQuery的json變得比較嚴格,會調用本機的json.Parse來轉換,如果存在什么雙引號,單引號之類的不符合要求,則不會成功轉換,並且不會進入到success。這樣一來,.Net本身提供的序列化方法都不能用了。因此,建議還是使用dataType:text 然后再自己轉換。
C#對象轉Json
要引用System.Runtime.Serialization.dll
第一個例子:C#后台將對象轉換為Json格式,然后由前台解釋:
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult GetJson() { Person p = new Person(1, "關羽", 20); string str = ObjToJson2<Person>(p); //return Json(p,JsonRequestBehavior.AllowGet); 這種方法也行,而且是.Net提供的,有這個的時候,用這個比較好,沒有就自己搞的。 return Content(str); } //單個對象轉Json 方法1 public static string ObjToJson1<T>(T data) { JavaScriptSerializer jss = new JavaScriptSerializer(); string JsonStr = jss.Serialize(data); return JsonStr; } //單個對象轉Json 方法2 //要特別注意,方法2要對類以及類的成員加上特性 public static string ObjToJson2<T>(T obj) { try { System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType()); using (MemoryStream ms = new MemoryStream()) { serializer.WriteObject(ms, obj); byte[] byteArr = ms.ToArray(); return Encoding.UTF8.GetString(byteArr); } } catch(Exception ex) { return null; } } } [DataContract] //該類中的特性是對於System.Runtime.Serialization.Json.DataContractJsonSerializer即方法2的轉Json設置的,不設置不行。 public class Person { public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } [DataMember] //對方法2要設置成員屬性 public int Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } }
/Home/Index視圖代碼:
<html> <head> <title>Json測試</title> <script src="/Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $.ajax({ url: "/Home/GetJson", dataType: "text", success: function (response) { alert(response); var obj = strToJson(response); $("#div1").html("姓名:" + obj.Name + " " + "年齡:" + obj.Age); alert(obj.Name); } }) }) function strToJson(str) { var json = eval('(' + str + ')'); return json; } </script> </head> <body> <div id="div1"> </div> </body> </html>
輸出結果如下:
Json字符串轉Model
這里實現的例子是,前台用js拼接一段Json字符串,傳送上后台,后台再解釋為C#對象,並將年齡+1后返回該對象的Json。
后台代碼:
namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult JsonToModel(string json) { Person p = ParseFromJson<Person>(json); p.Age = p.Age + 1; //將年齡加大一歲,在序列化返回去 return Json(p,JsonRequestBehavior.AllowGet); } /// <summary> /// 獲取Json的Model /// </summary> /// <typeparam name="T"></typeparam> /// <param name="szJson"></param> /// <returns></returns> public static T ParseFromJson<T>(string szJson) { T obj = Activator.CreateInstance<T>(); //注意 要有T類型要有無參構造函數 using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(szJson))) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType()); return (T)serializer.ReadObject(ms); } } } [DataContract] //該類中的特性是對於System.Runtime.Serialization.Json.DataContractJsonSerializer即方法2的轉Json設置的,不設置不行。 public class Person { public Person() { } public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } [DataMember] //對方法2要設置成員屬性 public int Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } } }
前台代碼:
<html> <head> <title>Json測試</title> <script src="/Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { var o = { Id: 1, Name: "劉備", Age: 23 }; $.ajax({ url: "/Home/JsonToModel", dataType: "text", type:"post", data:{ json: JSON.stringify(o) //將o序列化為字符串 }, success: function (response) { alert(response); var obj = strToJson(response); $("#div1").html("姓名:" + obj.Name + " " + "年齡:" + obj.Age); alert(obj.Name); } }) }) function strToJson(str) { var json = eval('(' + str + ')'); return json; } </script> </head> <body> <div id="div1"> </div> </body> </html>
注意到我們前台拼接的年齡是23。但是返回的是24,說明已經拼接成功了。
DataTable轉JSON
這里例子是在DataTable轉換為JSON的方法,其中還包括了前台javascript解釋:
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult GetJson() { DataTable dt = new DataTable(); dt.Columns.Add("Id"); dt.Columns.Add("Name"); dt.Columns.Add("Age"); dt.Rows.Add("1", "關羽", "22"); dt.Rows.Add("2", "趙雲", "23"); dt.Rows.Add("3", "張飛", "21"); //string strJson = DataTableToJson1(dt); string strJson = dt.ToJson(); //return Json(dt, JsonRequestBehavior.AllowGet); //貌似這個是不支持的,不支持直接將DataTable轉換為Json return Content(strJson); } ///<summary> ///方法1 這個方法其實就是DataTable拼接成字符串而已,沒什么出奇的 ///</summary> ///<param name="dt"></param> ///<returns></returns> public static string DataTableToJson1(DataTable dt) { if (dt.Rows.Count == 0) { return ""; } StringBuilder jsonBuilder = new StringBuilder(); jsonBuilder.Append("["); for (int i = 0; i < dt.Rows.Count; i++) { jsonBuilder.Append("{"); for (int j = 0; j < dt.Columns.Count; j++) { jsonBuilder.Append("\""); jsonBuilder.Append(dt.Columns[j].ColumnName); jsonBuilder.Append("\":\""); jsonBuilder.Append(dt.Rows[i][j].ToString()); jsonBuilder.Append("\","); } jsonBuilder.Remove(jsonBuilder.Length - 1, 1); jsonBuilder.Append("},"); } jsonBuilder.Remove(jsonBuilder.Length - 1, 1); jsonBuilder.Append("]"); return jsonBuilder.ToString(); } } /// <summary> /// 寫成DataTable的擴展方法是這樣 /// </summary> public static class JsonTableHelper { /// <summary> /// 返回對象序列化 /// </summary> /// <param name="obj">源對象</param> /// <returns>json數據</returns> public static string ToJson(object obj) { JavaScriptSerializer serialize = new JavaScriptSerializer(); return serialize.Serialize(obj); } /// <summary> /// 控制深度 /// </summary> /// <param name="obj">源對象</param> /// <param name="recursionDepth">深度</param> /// <returns>json數據</returns> public static string ToJson(object obj, int recursionDepth) { JavaScriptSerializer serialize = new JavaScriptSerializer(); serialize.RecursionLimit = recursionDepth; return serialize.Serialize(obj); } /// <summary> /// DataTable轉為json /// </summary> /// <param name="dt">DataTable</param> /// <returns>json數據</returns> public static string ToJson(this DataTable dt) { List<object> dic = new List<object>(); foreach (DataRow dr in dt.Rows) { Dictionary<string, object> result = new Dictionary<string, object>(); foreach (DataColumn dc in dt.Columns) { result.Add(dc.ColumnName, dr[dc].ToString()); } dic.Add(result); } return ToJson(dic); } }
其中/Home/Index的視圖代碼為:
<html> <head> <title>Json測試</title> <script src="/Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $.ajax({ url: "/Home/GetJson", dataType: "text", success: function (response) { alert(response); var obj = strToJson(response); var str = ""; for (var i = 0; i < obj.length; i++) { str += "姓名:" + obj[i].Name + " " + "年齡:" + obj[i].Age; } $("#div1").html(str); } }) }) function strToJson(str) { var json = eval('(' + str + ')'); return json; } </script> </head> <body> <div id="div1"> </div> </body> </html>
輸出結果如下:
List<T>轉Json
List<T>轉Json從方法上來說,與普通對象轉Json代碼是一樣的,因此這也是為什么微軟的JsonResult能夠正確返回Json字符串的原因了。
后台代碼:
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult GetJson() { List<Person> list = new List<Person>(); list.Add(new Person(1, "張飛", 21)); list.Add(new Person(2, "關羽", 22)); list.Add(new Person(3, "劉備", 23)); //return Json(list,JsonRequestBehavior.AllowGet); //.Net還是很威武的,這行代碼是可以運行並得到正確結果的,然后注釋來看看前輩們的List<T>轉Json的代碼// string strJson = ObjToJson<List<Person>>(list); //泛泛型? 這代碼怎么感覺怪怪的。 return Content(strJson); } [NonAction] public static string ObjToJson<T>(T data) { try { System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(data.GetType()); using (MemoryStream ms = new MemoryStream()) { serializer.WriteObject(ms, data); return Encoding.UTF8.GetString(ms.ToArray()); } } catch { return null; } } } [DataContract] //該類中的特性是對於System.Runtime.Serialization.Json.DataContractJsonSerializer即方法2的轉Json設置的,不設置不行。 public class Person { public Person() { } public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } [DataMember] //對方法2要設置成員屬性 public int Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } }
/Home/Index視圖代碼,這個與DataTable是一樣的,反正都是轉成數組的Json字符串。
<html> <head> <title>Json測試</title> <script src="/Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $.ajax({ url: "/Home/GetJson", dataType: "text", success: function (response) { alert(response); var obj = strToJson(response); var str = ""; for (var i = 0; i < obj.length; i++) { str += "姓名:" + obj[i].Name + " " + "年齡:" + obj[i].Age; } $("#div1").html(str); } }) }) function strToJson(str) { var json = eval('(' + str + ')'); return json; } </script> </head> <body> <div id="div1"> </div> </body> </html>
JSON轉List<T>
本次的例子是先在本地拼接一個Json對象,然后發送到后台轉成List<T>對象,再循環,年齡+10再返回Json
后台代碼:
public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult GetJson(string json) { List<Person> list = JsonToObj(json, typeof(List<Person>)) as List<Person>; //貌似List<T> 與 普通類型是一樣的 注意得到list的數量 //循環將年齡+10后再返回Json for (int i = 0; i < list.Count; i++) { list[i].Age = list[i].Age + 10; } return Json(list,JsonRequestBehavior.AllowGet); //.Net還是很威武的,這行代碼是可以運行並得到正確結果的,然后注釋來看看前輩們的List<T>轉Json的代碼 } public static Object JsonToObj(String json, Type t) { try { System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(t); using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) { return serializer.ReadObject(ms); } } catch { return null; } } } [DataContract] //該類中的特性是對於System.Runtime.Serialization.Json.DataContractJsonSerializer即方法2的轉Json設置的,不設置不行。 public class Person { public Person() { } public Person(int id, string name, int age) { Id = id; Name = name; Age = age; } [DataMember] //對方法2要設置成員屬性 public int Id { get; set; } [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } }
前台Html代碼:
<html> <head> <title>Json測試</title> <script src="/Scripts/jquery-1.7.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { var o1 = { Id: 1, Name: "張三", Age: 21 }; var o2 = { Id: 2, Name: "李四", Age: 22 }; var o3 = { Id: 3, Name: "王五", Age: 23 }; var arr = [o1, o2, o3]; var str = JSON.stringify(arr); $.ajax({ url: "/Home/GetJson", dataType: "text", data: { json:str }, type:"post", success: function (response) { alert(response); var obj = strToJson(response); var str = ""; for (var i = 0; i < obj.length; i++) { str += "姓名:" + obj[i].Name + " " + "年齡:" + obj[i].Age; } $("#div1").html(str); } }) }) function strToJson(str) { var json = eval('(' + str + ')'); return json; } </script> </head> <body> <div id="div1"> </div> </body> </html>
輸出結果如圖所示:
留意到年齡已經全部加10了。
下面再給出一個不錯的方法:
JavaScriptSerializer sr = new JavaScriptSerializer(); JQGrilBind jqgb = sr.Deserialize(filters, typeof(JQGrilBind)) as JQGrilBind; //filters為json字符串
MVC return Json()注意事項
對於MVC中return Json()這個默認的輔助方法。
1、如果傳入的是對象,那么轉Json出來的對象就是javascript對象。
2、如果傳入的是List<Model>、Array這種類型的數據,那么轉Json出來的是javascript數組。
因此,要注意下,比如對於jQueryEasyUI的Tree來說,如果它接受的是javascript數組,那么就要返回對應的格式。