一、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数组,那么就要返回对应的格式。