一个.NET通用JSON解析/构建类的实现(c#)
在.NET Framework 3.5中已经提供了一个JSON对象的序列化工具,但是他是强类型的,必须先按JSON对象的格式定义一个类型,并将类型加上JSON序列化特性。本文将试图提供一个高度灵活的JSON通用类型(JsonObject),实现对JSON的解析及序列化。
假设JSON对象内容如下:
-
{
-
orders: {
-
date: '21:31:59',
-
name: 'Xfrog',
-
books: [{
-
name: 'C# 网络核心编程',
-
publish: '2010-3-24'
-
}, {
-
name: 'C#入门经典中文版',
-
publish: '2009-10-16'
-
}]
-
},
-
blog: 'http://www.cnblogs.com/xfrog'
-
}
使用JsonObject来构建,可选择以下三种方式:
方式一:
-
//通过标准构造函数
-
JsonObject json = new JsonObject();
-
json["orders"] = new JsonProperty(new JsonObject());
-
json["blog"] = new JsonProperty("http://www.cnblogs.com/xfrog");
-
JsonObject config = json.Properties<JsonObject>("orders");
-
json["orders"]["date"] = new JsonProperty(DateTime.Now.ToLongTimeString());
-
json["orders"]["name"] = new JsonProperty("Xfrog");
-
json["orders"]["books"] = new JsonProperty();
-
JsonProperty book = json["orders"]["books"].Add(new JsonObject());
-
book["name"] = new JsonProperty("C# 网络核心编程");
-
book["publish"] = new JsonProperty("2010-3-24");
-
book = json["orders"]["books"].Add(new JsonObject());
-
book["name"] = new JsonProperty("C#入门经典中文版");
-
book["publish"] = new JsonProperty("2009-10-16");
方式二:
-
//通过回调函数简化对象的构建
-
JsonObject json2 = new JsonObject((a) =>
-
{
-
a["orders"] = new JsonProperty(new JsonObject((b) =>
-
{
-
b["date"] = new JsonProperty(DateTime.Now.ToLongTimeString());
-
b["name"] = new JsonProperty("Xfrog");
-
b["books"] = new JsonProperty();
-
b["books"].Add(new JsonObject((c) =>
-
{
-
c["name"] = new JsonProperty("C# 网络核心编程");
-
c["publish"] = new JsonProperty("2010-3-24");
-
}));
-
b["books"].Add(new JsonObject((c) =>
-
{
-
c["name"] = new JsonProperty("C#入门经典中文版");
-
c["publish"] = new JsonProperty("2009-10-16");
-
}));
-
}));
-
a["blog"] = new JsonProperty("http://www.cnblogs.com/xfrog");
-
});
方式三:
-
//通过字符串构建Json对象
-
JsonObject newObj = new JsonObject(jsonStr);
获取Json对象属性值的方法,也有三种方式:
-
//通过泛型函数
-
Console.WriteLine(newObj["orders"].GetValue<JsonObject>()["books"].GetValue<List<JsonProperty>>()[1].GetValue<JsonObject>()["name"].Value);
-
//通过属性类型对应的属性
-
Console.WriteLine(newObj["orders"].Object["books"].Items[1].Object["name"].Value);
-
//如果属性为对象类型,可通过字符串索引简化
-
Console.WriteLine(newObj["orders"]["books"][1]["name"].Value);
通用类:代码/********************************************************** * 作者:wHaibo * Email:xfrogcn@163.com * 日期:2010-04-07 * 版本:1.0 * 说明:Json通用转换类 *********************************************************/ using System; using System.Collections.Generic; using System.Text; namespace Xfrog.Net { /// <summary> /// 用于构建属性值的回调 /// </summary> /// <param name="Property"></param> public delegate void SetProperties(JsonObject Property); /// <summary> /// JsonObject属性值类型 /// </summary> public enum JsonPropertyType { String, Object, Array, Number, Bool, Null } /// <summary> /// JSON通用对象 /// </summary> public class JsonObject { private Dictionary<String, JsonProperty> _property; public JsonObject() { this._property = null; } public JsonObject(String jsonString) { this.Parse(ref jsonString); } public JsonObject(SetProperties callback) { if (callback != null) { callback(this); } } /// <summary> /// Json字符串解析 /// </summary> /// <param name="jsonString"></param> private void Parse(ref String jsonString) { int len = jsonString.Length; bool poo = string.IsNullOrEmpty(jsonString); string po = jsonString.Substring(0, 1); string ll = jsonString.Substring(jsonString.Length - 1, 1); if (String.IsNullOrEmpty(jsonString) || jsonString.Substring(0, 1) != "{" || jsonString.Substring(jsonString.Length - 1, 1) != "}") { throw new ArgumentException("传入文本不符合Json格式!" + jsonString); } Stack<Char> stack = new Stack<char>(); Stack<Char> stackType = new Stack<char>(); StringBuilder sb = new StringBuilder(); Char cur; bool convert = false; bool isValue = false; JsonProperty last = null; for (int i = 1; i <= len - 2; i++) { cur = jsonString[i]; if (cur == '}') { ; } if (cur == ' ' && stack.Count == 0) { ; } else if ((cur == '\'' || cur == '\"') && !convert && stack.Count == 0 && !isValue) { sb.Length = 0; stack.Push(cur); } else if ((cur == '\'' || cur == '\"') && !convert && stack.Count > 0 && stack.Peek() == cur && !isValue) { stack.Pop(); } else if ( (cur == '[' || cur == '{') && stack.Count == 0) { stackType.Push(cur == '[' ? ']' : '}'); sb.Append(cur); } else if ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Peek() == cur) { stackType.Pop(); sb.Append(cur); } else if (cur == ':' && stack.Count == 0 && stackType.Count == 0 && !isValue) { last = new JsonProperty(); this[sb.ToString()] = last; isValue = true; sb.Length = 0; } else if (cur == ',' && stack.Count == 0 && stackType.Count == 0) { if (last != null) { String temp = sb.ToString(); last.Parse(ref temp); } isValue = false; sb.Length = 0; } else { sb.Append(cur); } } if (sb.Length > 0 && last != null && last.Type == JsonPropertyType.Null) { String temp = sb.ToString(); last.Parse(ref temp); } } /// <summary> /// 获取属性 /// </summary> /// <param name="PropertyName"></param> /// <returns></returns> public JsonProperty this[String PropertyName] { get { JsonProperty result = null; if (this._property != null && this._property.ContainsKey(PropertyName)) { result = this._property[PropertyName]; } return result; } set { if (this._property == null) { this._property = new Dictionary<string, JsonProperty>(StringComparer.OrdinalIgnoreCase); } if (this._property.ContainsKey(PropertyName)) { this._property[PropertyName] = value; } else { this._property.Add(PropertyName, value); } } } /// <summary> /// 通过此泛型函数可直接获取指定类型属性的值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="PropertyName"></param> /// <returns></returns> public virtual T Properties<T>(String PropertyName) where T : class { JsonProperty p = this[PropertyName]; if (p != null) { return p.GetValue<T>(); } return default(T); } /// <summary> /// 获取属性名称列表 /// </summary> /// <returns></returns> public String[] GetPropertyNames() { if (this._property == null) return null; String[] keys = null; if (this._property.Count > 0) { keys = new String[this._property.Count]; this._property.Keys.CopyTo(keys, 0); } return keys; } /// <summary> /// 移除一个属性 /// </summary> /// <param name="PropertyName"></param> /// <returns></returns> public JsonProperty RemoveProperty(String PropertyName) { if (this._property != null && this._property.ContainsKey(PropertyName)) { JsonProperty p = this._property[PropertyName]; this._property.Remove(PropertyName); return p; } return null; } /// <summary> /// 是否为空对象 /// </summary> /// <returns></returns> public bool IsNull() { return this._property == null; } public override string ToString() { return this.ToString(""); } /// <summary> /// ToString... /// </summary> /// <param name="format">格式化字符串</param> /// <returns></returns> public virtual string ToString(String format) { if (this.IsNull()) { return "{}"; } else { StringBuilder sb = new StringBuilder(); foreach (String key in this._property.Keys) { sb.Append(","); sb.Append(key).Append(": "); sb.Append(this._property[key].ToString(format)); } if (this._property.Count > 0) { sb.Remove(0, 1); } sb.Insert(0, "{"); sb.Append("}"); return sb.ToString(); } } } /// <summary> /// JSON对象属性 /// </summary> public class JsonProperty { private JsonPropertyType _type; private String _value; private JsonObject _object; private List<JsonProperty> _list; private bool _bool; private double _number; public JsonProperty() { this._type = JsonPropertyType.Null; this._value = null; this._object = null; this._list = null; } public JsonProperty(Object value) { this.SetValue(value); } public JsonProperty(String jsonString) { this.Parse(ref jsonString); } /// <summary> /// Json字符串解析 /// </summary> /// <param name="jsonString"></param> public void Parse(ref String jsonString) { if (String.IsNullOrEmpty(jsonString)) { this.SetValue(null); } else { string first = jsonString.Substring(0, 1); string last = jsonString.Substring(jsonString.Length - 1, 1); if (first == "[" && last == "]") { this.SetValue(this.ParseArray(ref jsonString)); } else if (first == "{" && last=="}") { this.SetValue(this.ParseObject(ref jsonString)); } else if ((first == "'" || first == "\"") && first == last) { this.SetValue( this.ParseString(ref jsonString)); } else if (jsonString == "true" || jsonString == "false") { this.SetValue(jsonString == "true" ? true : false); } else if (jsonString == "null") { this.SetValue(null); } else { double d = 0; if (double.TryParse(jsonString, out d)) { this.SetValue(d); } else { this.SetValue(jsonString); } } } } /// <summary> /// Json Array解析 /// </summary> /// <param name="jsonString"></param> /// <returns></returns> private List<JsonProperty> ParseArray(ref String jsonString) { List<JsonProperty> list = new List<JsonProperty>(); int len = jsonString.Length; StringBuilder sb = new StringBuilder(); Stack<Char> stack = new Stack<char>(); Stack<Char> stackType = new Stack<Char>(); bool conver = false; Char cur; for (int i = 1; i <= len - 2; i++) { cur = jsonString[i]; if (Char.IsWhiteSpace(cur) && stack.Count == 0) { ; } else if ((cur == '\'' && stack.Count == 0 && !conver && stackType.Count == 0) || (cur == '\"' && stack.Count == 0 && !conver && stackType.Count == 0)) { sb.Length = 0; sb.Append(cur); stack.Push(cur); } else if (cur == '\\' && stack.Count > 0 && !conver) { sb.Append(cur); conver = true; } else if (conver == true) { conver = false; if (cur == 'u') { sb.Append(new char[] { cur, jsonString[i + 1], jsonString[i + 2], jsonString[i + 3] }); i += 4; } else { sb.Append(cur); } } else if ((cur == '\'' || cur == '\"') && !conver && stack.Count>0 && stack.Peek() == cur && stackType.Count == 0) { sb.Append(cur); list.Add(new JsonProperty(sb.ToString())); stack.Pop(); }else if( (cur == '[' || cur == '{' ) && stack.Count==0 ) { if (stackType.Count == 0) { sb.Length = 0; } sb.Append( cur); stackType.Push((cur == '[' ? ']' : '}')); } else if ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Count>0 && stackType.Peek() == cur) { sb.Append(cur); stackType.Pop(); if (stackType.Count == 0) { list.Add(new JsonProperty(sb.ToString())); sb.Length = 0; } } else if (cur == ',' && stack.Count == 0 && stackType.Count == 0) { if (sb.Length > 0) { list.Add(new JsonProperty(sb.ToString())); sb.Length = 0; } } else { sb.Append(cur); } } if (stack.Count > 0 || stackType.Count > 0) { list.Clear(); throw new ArgumentException("无法解析Json Array对象!"); } else if (sb.Length > 0) { list.Add(new JsonProperty(sb.ToString())); } return list; } /// <summary> /// Json String解析 /// </summary> /// <param name="jsonString"></param> /// <returns></returns> private String ParseString(ref String jsonString) { int len = jsonString.Length; StringBuilder sb = new StringBuilder(); bool conver = false; Char cur; for (int i = 1; i <= len - 2; i++) { cur = jsonString[i]; if (cur == '\\' && !conver) { conver = true; } else if (conver == true) { conver = false; if (cur == '\\' || cur == '\"' || cur == '\'' || cur == '/') { sb.Append(cur); } else { if (cur == 'u') { String temp = new String(new char[] { cur, jsonString[i + 1], jsonString[i + 2], jsonString[i + 3] }); sb.Append((char)Convert.ToInt32(temp, 16)); i += 4; } else { switch (cur) { case 'b': sb.Append('\b'); break; case 'f': sb.Append('\f'); break; case 'n': sb.Append('\n'); break; case 'r': sb.Append('\r'); break; case 't': sb.Append('\t'); break; } } } } else { sb.Append(cur); } } return sb.ToString(); } /// <summary> /// Json Object解析 /// </summary> /// <param name="jsonString"></param> /// <returns></returns> private JsonObject ParseObject(ref String jsonString) { return new JsonObject(jsonString); } /// <summary> /// 定义一个索引器,如果属性是非数组的,返回本身 /// </summary> /// <param name="index"></param> /// <returns></returns> public JsonProperty this[int index] { get { JsonProperty r = null; if (this._type == JsonPropertyType.Array) { if (this._list != null && (this._list.Count - 1) >= index) { r = this._list[index]; } } else if (index == 0) { return this; } return r; } } /// <summary> /// 提供一个字符串索引,简化对Object属性的访问 /// </summary> /// <param name="PropertyName"></param> /// <returns></returns> public JsonProperty this[String PropertyName] { get { if (this._type == JsonPropertyType.Object) { return this._object[PropertyName]; } else { return null; } } set { if (this._type == JsonPropertyType.Object) { this._object[PropertyName] = value; } else { throw new NotSupportedException("Json属性不是对象类型!"); } } } /// <summary> /// JsonObject值 /// </summary> public JsonObject Object { get { if (this._type == JsonPropertyType.Object) return this._object; return null; } } /// <summary> /// 字符串值 /// </summary> public String Value { get { if (this._type == JsonPropertyType.String) { return this._value; } else if (this._type == JsonPropertyType.Number) { return this._number.ToString(); } return null; } } public JsonProperty Add(Object value) { if (this._type != JsonPropertyType.Null && this._type != JsonPropertyType.Array) { throw new NotSupportedException("Json属性不是Array类型,无法添加元素!"); } if (this._list == null) { this._list = new List<JsonProperty>(); } JsonProperty jp = new JsonProperty(value); this._list.Add(jp); this._type = JsonPropertyType.Array; return jp; } /// <summary> /// Array值,如果属性是非数组的,则封装成只有一个元素的数组 /// </summary> public List<JsonProperty> Items { get { if (this._type == JsonPropertyType.Array) { return this._list; } else { List<JsonProperty> list = new List<JsonProperty>(); list.Add(this); return list; } } } /// <summary> /// 数值 /// </summary> public double Number { get { if (this._type == JsonPropertyType.Number) { return this._number; } else { return double.NaN; } } } public void Clear() { this._type = JsonPropertyType.Null; this._value = String.Empty; this._object = null; if (this._list != null) { this._list.Clear(); this._list = null; } } public Object GetValue() { if (this._type == JsonPropertyType.String) { return this._value; } else if (this._type == JsonPropertyType.Object) { return this._object; } else if (this._type == JsonPropertyType.Array) { return this._list; } else if (this._type == JsonPropertyType.Bool) { return this._bool; } else if (this._type == JsonPropertyType.Number) { return this._number; } else { return null; } } public virtual T GetValue<T>() where T : class { return (GetValue() as T); } public virtual void SetValue(Object value) { if (value is String) { this._type = JsonPropertyType.String; this._value = (String)value; } else if (value is List<JsonProperty>) { this._list = ((List<JsonProperty>)value); this._type = JsonPropertyType.Array; } else if (value is JsonObject) { this._object = (JsonObject)value; this._type = JsonPropertyType.Object; } else if (value is bool) { this._bool = (bool)value; this._type = JsonPropertyType.Bool; } else if (value == null) { this._type = JsonPropertyType.Null; } else { double d = 0; if (double.TryParse(value.ToString(), out d)) { this._number = d; this._type = JsonPropertyType.Number; } else { throw new ArgumentException("错误的参数类型!"); } } } public virtual int Count { get { int c = 0; if (this._type == JsonPropertyType.Array) { if (this._list != null) { c = this._list.Count; } } else { c = 1; } return c; } } public JsonPropertyType Type { get { return this._type; } } public override string ToString() { return this.ToString(""); } public virtual string ToString(String format) { StringBuilder sb = new StringBuilder(); if (this._type == JsonPropertyType.String) { sb.Append("'").Append(this._value).Append("'"); return sb.ToString(); } else if (this._type == JsonPropertyType.Bool) { return this._bool ? "true" : "false"; } else if (this._type == JsonPropertyType.Number) { return this._number.ToString(); } else if (this._type == JsonPropertyType.Null) { return "null"; } else if (this._type == JsonPropertyType.Object) { return this._object.ToString(); } else { if (this._list == null || this._list.Count == 0) { sb.Append("[]"); } else { sb.Append("["); if (this._list.Count > 0) { foreach (JsonProperty p in this._list) { sb.Append(p.ToString()); sb.Append(", "); } sb.Length-=2; } sb.Append("]"); } return sb.ToString(); } } } }
直接使用ToString函数,将JsonObject转换为Json字符串:
-
String jsonStr = json.ToString();
注意:
我在重载ToString函数时,并没有将字符串转换为JavsScript字符串类型(即对需要转义的字符的处理),当然,要实现也是极其简单的。另外,对于带String参数的ToString,我也为做特殊处理,感兴趣的朋友可自行实现。