JSON入门篇
一、简介
JSON: JavaScript Object Notation(JavaScript 对象表示法)
JSON 是存储和交换文本信息的语法,类似 XML。
JSON 比 XML 更小、更快,更易解析。
第一个JSON示例:这个 sites 对象是包含 3 个站点记录(对象)的数组。
{ "sites": [ { "name":"菜鸟教程" , "url":"www.runoob.com" }, { "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" } ] }
什么是 JSON ?
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
- JSON 具有自我描述性,更易理解
JSON - 转换为 JavaScript 对象
JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。
由于这种相似性,无需解析器,JavaScript 程序能够使用内建的 eval() 函数,用 JSON 数据来生成原生的 JavaScript 对象。
与 XML 相同之处
- JSON 是纯文本
- JSON 具有"自我描述性"(人类可读)
- JSON 具有层级结构(值中存在值)
- JSON 可通过 JavaScript 进行解析
- JSON 数据可使用 AJAX 进行传输
与 XML 不同之处
- 没有结束标签
- 更短
- 读写的速度更快
- 能够使用内建的 JavaScript eval() 方法进行解析
- 使用数组
- 不使用保留字
为什么使用 JSON?
对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:
使用 XML
- 读取 XML 文档
- 使用 XML DOM 来循环遍历文档
- 读取值并存储在变量中
使用 JSON
- 读取 JSON 字符串
- 用 eval() 处理 JSON 字符串
二、JSON 语法
JSON 语法规则
JSON 语法是 JavaScript 对象表示语法的子集。
- 数据在名称/值对中
- 数据由逗号分隔
- 大括号 {} 保存对象
- 中括号 [] 保存数组,数组可以包含多个对象
JSON 名称/值对
JSON 数据的书写格式是:
key : value
JSON 值
JSON 值可以是:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在中括号中)
- 对象(在大括号中)
- null
JSON 数字
JSON 数字可以是整型或者浮点型:
{ "age":30 }
JSON 对象
JSON 对象在大括号 {} 中书写:
{key1 : value1, key2 : value2, ... keyN : valueN }
JSON 数组
JSON 数组在中括号 [] 中书写:
数组可包含多个对象:
[ { key1 : value1-1 , key2:value1-2 }, { key1 : value2-1 , key2:value2-2 }, { key1 : value3-1 , key2:value3-2 }, ... { keyN : valueN-1 , keyN:valueN-2 }, ]
JSON 布尔值
JSON 布尔值可以是 true 或者 false:
{ "flag":true }
JSON null
JSON 可以设置 null 值:
{ "runoob":null }
三、JSON 对象
JSON 对象使用在大括号({})中书写。
对象可以包含多个 key/value(键/值)对。
key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
key 和 value 中使用冒号(:)分割。
每个 key/value 对使用逗号(,)分割。
访问对象值
你可以使用点号(.)来访问对象的值:
var myObj, x; myObj = { "name":"runoob", "alexa":10000, "site":null }; x = myObj.name;
你也可以使用中括号([])来访问对象的值:
var myObj, x; myObj = { "name":"runoob", "alexa":10000, "site":null }; x = myObj["name"];
循环对象
你可以使用 for-in 来循环对象的属性:
var myObj = { "name":"runoob", "alexa":10000, "site":null }; for (x in myObj) { document.getElementById("demo").innerHTML += x + "<br>"; }
在 for-in 循环对象的属性时,使用中括号([])来访问属性的值:
var myObj = { "name":"runoob", "alexa":10000, "site":null }; for (x in myObj) { document.getElementById("demo").innerHTML += myObj[x] + "<br>"; }
嵌套 JSON 对象
JSON 对象中可以包含另外一个 JSON 对象:
myObj = { "name":"runoob", "alexa":10000, "sites": { "site1":"www.runoob.com", "site2":"m.runoob.com", "site3":"c.runoob.com" } }
你可以使用点号(.)或者中括号([])来访问嵌套的 JSON 对象。
x = myObj.sites.site1; // 或者 x = myObj.sites["site1"];
删除对象属性
我们可以使用 delete 关键字来删除 JSON 对象的属性:
delete myObj.sites.site1;
Json 格式化工具 JSON 在线解析 | 菜鸟工具 (runoob.com)
.NET解析JSON
使用 Newtonsoft.Json 包解析
1、基本用法
Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework
和Entity
的。下面分别举例说明序列化和反序列化。
//序列化DataTable DataTable dt = new DataTable(); dt.Columns.Add("Age", Type.GetType("System.Int32")); dt.Columns.Add("Name", Type.GetType("System.String")); dt.Columns.Add("Sex", Type.GetType("System.String")); dt.Columns.Add("IsMarry", Type.GetType("System.Boolean")); for (int i = 0; i < 4; i++) { DataRow dr = dt.NewRow(); dr["Age"] = i + 1; dr["Name"] = "Name" + i; dr["Sex"] = i % 2 == 0 ? "男" : "女"; dr["IsMarry"] = i % 2 > 0 ? true : false; dt.Rows.Add(dr); } Console.WriteLine(JsonConvert.SerializeObject(dt)); //字符串进行反序列化 string json = JsonConvert.SerializeObject(dt); dt = JsonConvert.DeserializeObject<DataTable>(json); foreach (DataRow dr in dt.Rows) { Console.WriteLine("{0}\t{1}\t{2}\t{3}\t", dr[0], dr[1], dr[2], dr[3]); }
2、高级用法
- 忽略某些属性
- 默认值的处理
- 空值的处理
- 支持非公共成员
- 日期处理
- 自定义序列化的字段名称
- 动态决定属性是否序列化
- 枚举值的自定义格式化问题
- 自定义类型转换
- 全局序列化设置
2.1属性特性标记 通过JsonProperty
属性设置的方法,可以实现某一属性特别处理的需求,如默认值处理,空值处理,自定义属性名处理,格式化处理。上面空值处理实现
序列化时默认都是处理公共成员,如果需要处理非公共成员,就要在该成员上加特性[JsonProperty]
[JsonProperty(PropertyName = "图层颜色")] public int? ColorIndex { get; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Room room { get; set; }
[DefaultValue(10)] public int Age { get; set; }
[JsonIgnore] public bool IsMarry { get; set; }
2.2 对象特性标记 [JsonObject(MemberSerialization.OptOut)] 可以设置输出形式
[JsonObject(MemberSerialization.OptOut)] class LayerValue:ValueBase { [JsonProperty(PropertyName = "块名称")] public string? BlockName { get; } [JsonProperty(PropertyName = "图层名称")] public string? Layer { get; } [JsonProperty(PropertyName = "图层颜色")] public int? ColorIndex { get; } public LayerValue():base() { } }
2.3属性类型转换
枚举类型转换
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public FileMode Mode { get; set; } = FileMode.Create;
日期处理
对于Dateime
类型日期的格式化就比较麻烦了,系统自带的会格式化成iso
日期标准"Birthday":"1991-01-02T00:00:00
,但是实际使用过程中大多数使用的可能是yyyy-MM-dd
或者yyyy-MM-dd HH:mm:ss
两种格式的日期,
解决办法是可以将DateTime
类型改成string
类型自己格式化好,然后再序列化。如果不想修改代码,可以采用下面方案实现。Json.Net提供了IsoDateTimeConverter
日期转换这个类,可以通过JsnConverter
实现相应的日期转换
[JsonConverter(typeof(Newtonsoft.Json.Converters.IsoDateTimeConverter))] public DateTime Birthday { get; set; }
2.4自定义类型转换
自定义一个日期类型转换
[JsonConverter(typeof(ChinaDateTimeConverter))] public DateTime Birthday { get; set; }
/// <summary> /// 自己实现了一个yyyy-MM-dd格式化转换类 /// </summary> public class ChinaDateTimeConverter : Newtonsoft.Json.Converters.DateTimeConverterBase { private static Newtonsoft.Json.Converters.IsoDateTimeConverter dtConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" }; public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return dtConverter.ReadJson(reader, objectType, existingValue, serializer); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { dtConverter.WriteJson(writer, value, serializer); } }
自定义了BoolConvert
类型,继承自JsonConverter
。构造函数参数BooleanString
可以让我们自定义将true false
转换成相应字符串。下面看实体里面怎么使用这个自定义转换类型
默认情况下对于实体里面的Boolean
系统是格式化成true
或者false
,对于true
转成"是" false
转成"否"这种需求改怎么实现了?我们可以自定义类型转换实现该需求,下面看实例
[JsonConverter(typeof(BoolConvert))] public bool IsMarry { get; set; }
public class BoolConvert : JsonConverter { private string[] arrBString { get; set; } public BoolConvert() { arrBString = "是,否".Split(','); } /// <summary> /// 构造函数 /// </summary> /// <param name="BooleanString">将`bool`值转换成的字符串值</param> public BoolConvert(string BooleanString) { if (string.IsNullOrEmpty(BooleanString)) { throw new ArgumentNullException(); } arrBString = BooleanString.Split(','); if (arrBString.Length != 2) { throw new ArgumentException("BooleanString格式不符合规定"); } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { bool isNullable = IsNullableType(objectType); Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; if (reader.TokenType == JsonToken.Null) { if (!IsNullableType(objectType)) { throw new Exception(string.Format("不能转换null value to {0}.", objectType)); } return null; } try { if (reader.TokenType == JsonToken.String) { string boolText = reader.Value.ToString(); if (boolText.Equals(arrBString[0], StringComparison.OrdinalIgnoreCase)) { return true; } else if (boolText.Equals(arrBString[1], StringComparison.OrdinalIgnoreCase)) { return false; } } if (reader.TokenType == JsonToken.Integer) { return Convert.ToInt32(reader.Value) == 1; } } catch { throw new Exception(string.Format("Error converting value {0} to type '{1}'", reader.Value, objectType)); } throw new Exception(string.Format("Unexpected token {0} when parsing enum", reader.TokenType)); } /// <summary> /// 判断是否为`Bool`类型 /// </summary> /// <param name="objectType">类型</param> /// <returns>为`bool`类型则可以进行转换</returns> public override bool CanConvert(Type objectType) { return true; } public bool IsNullableType(Type t) { if (t == null) { throw new ArgumentNullException("t"); } return (t.BaseType.FullName == "System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } bool bValue = (bool)value; if (bValue) { writer.WriteValue(arrBString[0]); } else { writer.WriteValue(arrBString[1]); } } }
2.5自定义属性解析类
JsonSerializerSettings jsetting = new JsonSerializerSettings(); jsetting.ContractResolver = new LimitPropsContractResolver(new string[] { nameof(LayerValue.Name), nameof(LayerValue.ColorIndex) }); Console.WriteLine(JsonConvert.SerializeObject(layerValue, Formatting.Indented, jsetting));
public class LimitPropsContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver { string[] props = null; bool retain; /// <summary> /// 构造函数 /// </summary> /// <param name="props">传入的属性数组</param> /// <param name="retain">true:表示`props`是需要保留的字段`false`:表示`props`是要排除的字段</param> public LimitPropsContractResolver(string[] props, bool retain = true) { //指定要序列化属性的清单 this.props = props; this.retain = retain; } protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { IList<JsonProperty> list = base.CreateProperties(type, memberSerialization); //只保留清单有列出的属性 return list.Where(p => { if (retain) { return props.Contains(p.PropertyName); } else { return !props.Contains(p.PropertyName); } }).ToList(); } }
全局设置
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings(); JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() => { //日期类型默认格式化处理 setting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; setting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; //空值处理 setting.NullValueHandling = NullValueHandling.Ignore; //高级用法九中的`Bool`类型转换设置 //setting.Converters.Add(new BoolConvert("是,否")); return setting; });
序列化为文件
WeatherForecast weatherForecast = new WeatherForecast { Date = DateTime.Now, TemperatureCelsius = 20, Summary = "it is a good day!" }; string jsonString = JsonConvert.SerializeObject(weatherForecast, Formatting.Indented); File.WriteAllText("weather.json", jsonString);
从资源文件读取json
Assembly assm = Assembly.GetExecutingAssembly(); using (var reader = new StreamReader( assm.GetManifestResourceStream("ConsoleApp.Jsons.weatherPocos.json"))) { using (JsonTextReader jsonText = new JsonTextReader(reader)) { JObject jsonObject = (JObject)Newtonsoft.Json.Linq.JToken.ReadFrom(jsonText); Console.WriteLine(jsonObject); var withPOCOs = JsonConvert.DeserializeObject<WeatherForecastWithPOCOs>(jsonObject.ToString()); } }
保存内容到本地文件
string jsonString; using (var reader = new StreamReader(assm.GetManifestResourceStream("ConsoleApp.Jsons.weatherPocos.json"), System.Text.Encoding.UTF8)) { jsonString = reader.ReadToEnd(); } JObject jobject = JObject.Parse(jsonString);//解析成json string convertString = Convert.ToString(jobject);//将json装换为string File.WriteAllText("ConsoleApp.Jsons.weatherPocos.json", convertString, System.Text.Encoding.UTF8);//将内容写进jon文件中
参考链接 C# Newtonsoft.Json 高级用法 - 五维思考 - 博客园 (cnblogs.com) // Newtonsoft—Json.NET常用方法简述 (lagou.com)
https://blog.csdn.net/q__y__L/article/details/116922418
从 Newtonsoft.Json 迁移到 System.Text.Json - .NET | Microsoft Docs