JSON

1.JSON是什么

JSON 是一种用于数据交换的文本格式,诞生于 2001 年由Douglas Crockford提出,目的是取代繁琐笨重的XML格式。这种格式不仅人很容易进行阅读和编写,同时机器也很容易解析和生成,是当前十分流行的数据格式,尤其是在前端领域。

JSON,全称是 JavaScript Object Notation,即 JavaScript 对象标记法。这是一种 轻量级 (Light-Weight)、 基于文本的 (Text-Based)、 可读的 (Human-Readable)格式。

  JSON 无论对于人,还是对于机器来说,都是十分便于阅读和书写的,而且相比 XML 文件更小;

  JSON 格式的创始人声称此格式永远不升级,这就表示这种格式具有长时间的稳定性;

  JSON格式有两个显著的优点:书写简单,一目了然;符合JavaScript原生语法,可以由解释引擎直接处理,不用另外添加解析代码。

  JSON已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。

  简单说,每个JSON对象,就是一个值。要么是简单类型的值,要么是复合类型的值,但是只能是一个值,不能是两个或更多的值。这就是说,每个JSON文档只能包含一个值。



2.JSON有哪两种结构

1、对象:对象在js中表示为“{}”括起来的内容,数据结构为 {key:value,key:value,...}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是 数字、字符串、数组、对象几种:

   名称\值对    

           按照最简单的形式,可以用下面这样的 JSON 表示"名称 / 值对":

1
{"firstName":"Brett"}
这个示例非常基本,而且实际上比等效的纯文本"名称 / 值对"占用更多的空间:
1
firstName=Brett
但是,当将多个"名称 / 值对"串在一起时,JSON 就会体现出它的价值了。首先,可以创建包含多个"名称 / 值对"的 记录,比如:
1
{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"}
从语法方面来看,这与"名称 / 值对"相比并没有很大的优势,但是在这种情况下 JSON 更容易使用,而且可读性更好。例如,它明确地表示以上三个值都是同一记录的一部分;花括号使这些值有了某种联系。



2、数组:数组在js中是中括号“[]”括起来的内容,数据结构为 ["java","javascript","vb",...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种:

     

当需要表示一组值时,JSON 不但能够提高可读性,而且可以减少复杂性。例如,假设您希望表示一个人名列表。在 XML中,需要许多开始标记和结束标记;如果使用典型的名称 / 值对(就像在本系列前面文章中看到的那种名称 / 值对),那么必须建立一种专有的数据格式,或者将键名称修改为 person1-firstName这样的形式。
如果使用 JSON,就只需将多个带花括号的记录分组在一起:
1
2
3
4
5
6
7
{
     "people":[
         {"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},
         {"firstName":"Jason","lastName":"Hunter","email":"bbbb"},
         {"firstName":"Elliotte","lastName":"Harold","email":"cccc"}
     ]
}
这不难理解。在这个示例中,只有一个名为 people的变量,值是包含三个条目的数组,每个条目是一个人的记录,其中包含名、姓和电子邮件地址。上面的示例演示如何用括号将记录组合成一个值。当然,可以使用相同的语法表示多个值(每个值包含多个记录):
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
{
     "programmers": [{
         "firstName": "Brett",
         "lastName": "McLaughlin",
         "email": "aaaa"
     }, {
         "firstName": "Jason",
         "lastName": "Hunter",
         "email": "bbbb"
     }, {
         "firstName": "Elliotte",
         "lastName": "Harold",
         "email": "cccc"
     }],
     "authors": [{
         "firstName": "Isaac",
         "lastName": "Asimov",
         "genre": "sciencefiction"
     }, {
         "firstName": "Tad",
         "lastName": "Williams",
         "genre": "fantasy"
     }, {
         "firstName": "Frank",
         "lastName": "Peretti",
         "genre": "christianfiction"
     }],
     "musicians": [{
         "firstName": "Eric",
         "lastName": "Clapton",
         "instrument": "guitar"
     }, {
         "firstName": "Sergei",
         "lastName": "Rachmaninoff",
         "instrument": "piano"
     }]
}
这里最值得注意的是,能够表示多个值,每个值进而包含多个值。但是还应该注意,在不同的主条目(programmers、authors 和 musicians)之间,记录中实际的名称 / 值对可以不一样。JSON 是完全动态的,允许在 JSON 结构的中间改变表示数据的方式。
在处理 JSON 格式的数据时,没有需要遵守的预定义的约束。所以,在同样的数据结构中,可以改变表示数据的方式,甚至可以以不同方式表示同一事物。

可以创建一个新的 JavaScript 变量,然后将 JSON 格式的数据字符串直接赋值给它:
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
var people = {
     "programmers": [{
         "firstName": "Brett",
         "lastName": "McLaughlin",
         "email": "aaaa"
     }, {
         "firstName": "Jason",
         "lastName": "Hunter",
         "email": "bbbb"
     }, {
         "firstName": "Elliotte",
         "lastName": "Harold",
         "email": "cccc"
     }],
     "authors": [{
         "firstName": "Isaac",
         "lastName": "Asimov",
         "genre": "sciencefiction"
     }, {
         "firstName": "Tad",
         "lastName": "Williams",
         "genre": "fantasy"
     }, {
         "firstName": "Frank",
         "lastName": "Peretti",
         "genre": "christianfiction"
     }],
     "musicians": [{
         "firstName": "Eric",
         "lastName": "Clapton",
         "instrument": "guitar"
     }, {
         "firstName": "Sergei",
         "lastName": "Rachmaninoff",
         "instrument": "piano"
     }]
};
   
尽管看起来不明显,但是上面的长字符串实际上只是一个 数组;将这个数组放进 JavaScript变量之后,就可以很轻松地访问它。实际上,只需用点号表示法来表示数组元素。所以,要想访问 programmers 列表的第一个条目的姓氏,只需在 JavaScript 中使用下面这样的代码:
1
people.programmers[0].lastName;
注意,数组索引是从零开始的。所以,这行代码首先访问 people变量中的数据;然后移动到称为 programmers的条目,再移动到第一个记录([0]);最后,访问 lastName键的值。结果是字符串值 “McLaughlin”。
下面是使用同一变量的几个示例。
1
2
3
people.authors[1].genre   // Value is "fantasy"
people.musicians[3].lastName  // Undefined. This refers to the fourth entry, and there isn't one
people.programmers[2].firstName  // Value is "Elliotte"
利用这样的语法,可以处理任何 JSON 格式的数据,而不需要使用任何额外的 JavaScript 工具包或 API。

修改数据

正如可以用点号和方括号访问数据,也可以按照同样的方式轻松地修改数据:
1
people.musicians[1].lastName= "Rachmaninov" ;
在将字符串转换为 JavaScript 对象之后,就可以像这样修改变量中的数据。

JSON嵌套格式

许多JavaScript树形控件使用JSON嵌套格式描述树形结构,如下所示:
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
{  
   id:  '100000' ,  
   text:  '廊坊银行总行' ,  
   children: [  
     {  
       id:  '110000' ,  
       text:  '廊坊分行' ,  
       children: [  
         {  
           id:  '113000' ,  
           text:  '廊坊银行开发区支行' ,  
           leaf:  true  
         },  
         {  
           id:  '112000' ,  
           text:  '廊坊银行解放道支行' ,  
           children: [  
             {  
               id:  '112200' ,  
               text:  '廊坊银行三大街支行' ,  
               leaf:  true  
             },  
             {  
               id:  '112100' ,  
               text:  '廊坊银行广阳道支行' ,  
               leaf:  true  
             }  
           ]  
         },  
         {  
           id:  '111000' ,  
           text:  '廊坊银行金光道支行' ,  
           leaf:  true  
         }  
       ]  
     }  
   ]  
}  
关于JSON嵌套格式可以搜索百度词条:“多叉树”。
      

具体形式

编辑
1、对象是一个无序的“‘名称/值’对”集合。
(1)一个对象以“{”(左括号)开始,“}”(右括号)结束。
(2)每个“名称”后跟一个“:”(冒号);
(3)“‘名称/值’ 对”之间使用“,”(逗号)分隔。(如图所示,图中表示数据的方式是类似非确定性 自动机的形式,没学过 编译原理的人,可能理解起来困难点,实际上也是 正则表达式的形式。下同)
例子:表示人的一个对象:
1
2
3
4
{
     "姓名":"大憨",
     "年龄":24
}
2、数组是值(value)的有序集合。
(1)一个数组以“[”(左中括号)开始,“]”(右中括号)结束。
(2)值之间使用“,”(逗号)分隔。
例子:一组学生
1
2
3
4
5
6
{
     "学生": [
         {"姓名":"小明","年龄":23},
         {"姓名":"大憨","年龄":24}
     ]
}
说明:此Json对象包括了一个学生数组,而学生数组中的值又是两个Json对象。
3、值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
4、 字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。 字符串(string)与C或者Java的字符串非常相似。
5、数值(number)也与C或者 Java的数值非常相似。除去未曾使用的 八进制与十六进制格式。除去一些编码细节。



3.如何解析JSONObject(附案例)

在Unity游戏开发中,使用Newton.Json来反序列化时,需要指定确定的类型,这会带来什么问题?

在游戏的道具系统中,有一个父类Item类,包含属性ID和Name,有一个子类Consumable消耗品类,包含属性HP和MP,UML如下:

后端返回的物品信息Json如下:

复制代码
[
    {
        "id": 1,
        "name": "血瓶",
        "type": "Consumable",
        "hp": 10,
        "mp": 0,
    },
    {
        "id": 2,
        "name": "蓝瓶",
        "type": "Consumable",
        "hp": 0,
        "mp": 10,
    }
]
复制代码

 

使用Newton.Json时,代码如下:

复制代码
// itemsJson是包含了物品信息的Json字符串
public void ParseItemJson(string itemsJson)
{
    List<Item> itemList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Item>>(itemsJson);

    foreach (Item temp in itemList)
    {
        int id = temp.ID;
        string name = temp.Name;
        Item.ItemType type = temp.Type;

        Item item = null;
        switch (type)
        {
            case Item.ItemType.Consumable:
                Consumable consumable = temp as Consumable;
                int hp = consumable.HP;
                int mp = consumable.MP;
                item = new Consumable(id, name, type, hp, mp);
                break;
            // 其他类型省略。。。
            default:
                break;
        }

itemList.Add(temp); } }
复制代码

按照以上思路,先以Item类型来反序列化,然后根据Item.Type来判断物品类的具体子类型,如果为Consumable消耗品类型,就获取该类型的HP和MP属性,再按消耗品类型来实例化对象。

但是由于反序列化时指定为Item类型,所以即便Json字符串中包含了HP和MP的内容,也不会被解析到Item对象身上。

 private List<Item> itemList = new List<Item>();
   
    /// <summary>
    /// 解析物品Json
    /// </summary>
    public void ParseItemJson(string itemsJson)
    {
        JSONObject j = new JSONObject(itemsJson);

        foreach (JSONObject temp in j.list)
        {
            int id = (int)temp["id"].n;
            string name = temp["name"].str;
            Item.ItemType type = (Item.ItemType)System.Enum.Parse(typeof(Item.ItemType), temp["type"].str);

            Item item = null;
            switch (type)
            {
                case Item.ItemType.Consumable:
                    int hp = (int)temp["hp"].n;
                    int mp = (int)temp["mp"].n;
                    item = new Consumable(id, name, type, hp, mp);
                    break;
                // 其他类型省略
                default:
                    break;
            }

            Debug.Log("item.id = " + item.ID + " , consumable.hp = " + ((Consumable)item).HP); itemList.Add(item); } }
复制代码


import java.util.List;

public class Teacher {
    private String name;
    private String sex;
    private int age;

    private List<Transport> myTool;
    
    
    public Teacher(){
        
    }
    
    public Teacher(String name,String sex,int age,List<Transport> myTool){
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.myTool = myTool;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Transport> getMyTool() {
        return myTool;
    }

    public void setMyTool(List<Transport> myTool) {
        this.myTool = myTool;
    }

}



4.如何解析JSONArray(附案例)

(1)基本使用:

复制代码
package com.snnu.json;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class demo_JsonArray {
    
    
    public JSONObject testJsonArray(){
        JSONObject ob=new JSONObject();
        
        JSONArray ja=new JSONArray();
        ja.add("1");
        ja.add("2");
        ja.add("3");
        ja.add("4");
        ja.add("5");
        
        ob.put("array", ja);
        
        return ob;
    }
    
    

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        demo_JsonArray djs=new demo_JsonArray();
        System.out.println("JSONArray的使用:"+djs.testJsonArray());
        
    }

}
复制代码

对输出后的字符串进行格式化:

复制代码
{
    "array": [
        "1",
        "2",
        "3",
        "4",
        "5"
    ]
}
复制代码

三、综合实例

复制代码
package com.snnu.json;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class demo_testJson {
    
    
    
    public JSONObject test(){
        
        JSONObject jo=new JSONObject();
        jo.put("name", "张三");
        jo.put("sex","f");
        jo.put("age",21);
        
        Transport bike=new Transport("bike",250);
        jo.put("extra", bike);
        Transport car=new Transport("car",10000);
        jo.accumulate("extra", car);
        Transport motor=new Transport("motor",3000);
        jo.accumulate("extra", motor);
        
        System.out.println(jo);
        
        //根据key值(为extra)取对应的value
        String value=jo.getString("extra");
        System.out.println(value);
        
        //将字符串转化为JSONArray
        JSONArray jsar=JSONArray.fromObject(value);
        String str_2=String.valueOf(jsar.get(1));
        System.out.println(str_2);
        
        //将字符串转化为JSONObject
        JSONObject jsob=JSONObject.fromObject(str_2);
        System.out.println("名称:"+jsob.getString("name"));
        System.out.println("价钱:"+jsob.getString("price"));
        
        System.out.println("-------------------------------分界线-------------------------------------------");
        
        return jo;
        
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        demo_testJson dtj=new demo_testJson();
        System.out.println("综合测试:"+dtj.test());
    }

}
复制代码

输出结果为:

复制代码
{"name":"张三","sex":"f","age":21,"extra":[{"name":"bike","price":250},{"name":"car","price":10000},{"name":"motor","price":3000}]}
[{"name":"bike","price":250},{"name":"car","price":10000},{"name":"motor","price":3000}]
{"name":"car","price":10000}
名称:car
价钱:10000
-------------------------------分界线-------------------------------------------
综合测试:{"name":"张三","sex":"f","age":21,"extra":[{"name":"bike","price":250},{"name":"car","price":10000},{"name":"motor","price":3000}]}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值