C#中json的增删改查

json 是 C# 中比较自由的数据存储格式,它的自由体现在可以不用声明很多类来规范数据格式就可以灵活地存取 json 对象。现将常用的增删查改操作方式整理出来,以便开发,以飨读者。

Json对象类图

1
2
3
4
5
6
7
8
9
System.Object
└── Newtonsoft.Json.Linq.JToken
├── Newtonsoft.Json.Linq.JValue
├── Newtonsoft.Json.Linq.JRaw
└── Newtonsoft.Json.Linq.JContainer
├── Newtonsoft.Json.Linq.JObject
├── Newtonsoft.Json.Linq.JArray
├── Newtonsoft.Json.Linq.JConstructor
└── Newtonsoft.Json.Linq.JProperty

转换

  1. 从文本转 Json Object

    1
    2
    3
    4
    5
    6
    7
    8
    9
    string json = @"{
    CPU: 'Intel',
    Drives: [
    'DVD read/writer',
    '500 gigabyte hard drive'
    ]
    }";

    JObject o = JObject.Parse(json);
  2. 从文本转 Json Array

    1
    2
    3
    4
    5
    6
    7
    string json = @"[
    'Small',
    'Medium',
    'Large'
    ]";

    JArray a = JArray.Parse(json);
  3. 从文件转 Json Object

    1
    2
    3
    4
    5
    using (StreamReader reader = File.OpenText(@"c:\person.json"))
    {
    JObject o = (JObject)JToken.ReadFrom(new JsonTextReader(reader));
    // do stuff
    }

创建

  1. 手动创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    JArray array = new JArray();
    JValue text = new JValue("Manual text");
    JValue date = new JValue(new DateTime(2000, 5, 23));

    array.Add(text);
    array.Add(date);

    string json = array.ToString();
    // [
    // "Manual text",
    // "2000-05-23T00:00:00"
    // ]
  2. 通过 Linq 创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    List<Post> posts = GetPosts();

    JObject rss =
    new JObject(
    new JProperty("channel",
    new JObject(
    new JProperty("title", "James Newton-King"),
    new JProperty("link", "http://james.newtonking.com"),
    new JProperty("description", "James Newton-King's blog."),
    new JProperty("item",
    new JArray(
    from p in posts
    orderby p.Title
    select new JObject(
    new JProperty("title", p.Title),
    new JProperty("description", p.Description),
    new JProperty("link", p.Link),
    new JProperty("category",
    new JArray(
    from c in p.Categories
    select new JValue(c)))))))));

    Console.WriteLine(rss.ToString());

    //{
    // "channel": {
    // "title": "James Newton-King",
    // "link": "http://james.newtonking.com",
    // "description": "James Newton-King\'s blog.",
    // "item": [
    // {
    // "title": "Json.NET 1.3 + New license + Now on CodePlex",
    // "description": "Announcing the release of Json.NET 1.3, the MIT license and being available on CodePlex",
    // "link": "http://james.newtonking.com/projects/json-net.aspx",
    // "category": [
    // "Json.NET",
    // "CodePlex"
    // ]
    // },
    // {
    // "title": "LINQ to JSON beta",
    // "description": "Announcing LINQ to JSON",
    // "link": "http://james.newtonking.com/projects/json-net.aspx",
    // "category": [
    // "Json.NET",
    // "LINQ"
    // ]
    // }
    // ]
    // }
    //}
  3. 通过匿名对象创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    JObject o = JObject.FromObject(new
    {
    channel = new
    {
    title = "James Newton-King",
    link = "http://james.newtonking.com",
    description = "James Newton-King's blog.",
    item =
    from p in posts
    orderby p.Title
    select new
    {
    title = p.Title,
    description = p.Description,
    link = p.Link,
    category = p.Categories
    }
    }
    });

修改

  1. 赋值修改

    1
    2
    JObject jobj = new JObject();
    jobj["name"] = "value"

查询

基本查询

  1. 通过名称或者索引访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    string json = @"{
    'channel': {
    'title': 'James Newton-King',
    'link': 'http://james.newtonking.com',
    'description': 'James Newton-King\'s blog.',
    'item': [
    {
    'title': 'Json.NET 1.3 + New license + Now on CodePlex',
    'description': 'Announcing the release of Json.NET 1.3, the MIT license and the source on CodePlex',
    'link': 'http://james.newtonking.com/projects/json-net.aspx',
    'categories': [
    'Json.NET',
    'CodePlex'
    ]
    },
    {
    'title': 'LINQ to JSON beta',
    'description': 'Announcing LINQ to JSON',
    'link': 'http://james.newtonking.com/projects/json-net.aspx',
    'categories': [
    'Json.NET',
    'LINQ'
    ]
    }
    ]
    }
    }";

    JObject rss = JObject.Parse(json);

    string rssTitle = (string)rss["channel"]["title"];
    // James Newton-King

    string itemTitle = (string)rss["channel"]["item"][0]["title"];
    // Json.NET 1.3 + New license + Now on CodePlex

    JArray categories = (JArray)rss["channel"]["item"][0]["categories"];
    // ["Json.NET", "CodePlex"]

    IList<string> categoriesText = categories.Select(c => (string)c).ToList();
    // Json.NET
    // CodePlex
  2. 通过 Linq 查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    var postTitles =
    from p in rss["channel"]["item"]
    select (string)p["title"];

    foreach (var item in postTitles)
    {
    Console.WriteLine(item);
    }

    //LINQ to JSON beta
    //Json.NET 1.3 + New license + Now on CodePlex

    var categories =
    from c in rss["channel"]["item"].SelectMany(i => i["categories"]).Values<string>()
    group c by c
    into g
    orderby g.Count() descending
    select new { Category = g.Key, Count = g.Count() };

    foreach (var c in categories)
    {
    Console.WriteLine(c.Category + " - Count: " + c.Count);
    }

    //Json.NET - Count: 2
    //LINQ - Count: 1
    //CodePlex - Count: 1

特殊查询

  1. 查询 JObject 中所有字段的名称

    1
    JProperty jp = inputObj.Properties();
  2. 如何在多级查询中避免不存在而报错?

    假设有如下数据结构:

    1
    2
    3
    4
    5
    6
    {
    "details": {
    "threeds2.fingerprint": "123"
    },
    "paymentData": "456"
    }

    查询方式:

    1
    jobj.SelectToken("details.['threeds2.fingerprint']")).ValueOrDefault(string.Empty)

    SelectToken方法支持我们输入深度Key的访问路径来获取数据,父子级使用"."连接;如果遇到key含有特殊符号点的,使用中括号加单引号包裹。而且这种写法不会抛出异常,如果路径错误或不存在返回值为null。

    ValueOrDefault 扩展:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static T ValueOrDefault<T>(this IEnumerable<JToken> jt, T default_)
    {
    if (jt == null) return default_;

    T value = jt.Value<T>();
    if (value == null) return default_;

    return value;
    }