【簡明教程】JSON

JSON概覽

JSON(JavaScript Object Notation)是一種基于文本的數(shù)據(jù)交換格式县踢。無論你的應用是用哪種開發(fā)語言編寫的(Java/EE,Ruby,PHP蛙粘,C#/.Net等等),你都可以使用JSON來通過網(wǎng)絡進行數(shù)據(jù)交互和處理威彰。幾乎所有的編程語言都有很好的庫或第三方工具來提供基于JSON的API支持出牧,因此你可以非常方便地使用任何自己喜歡的編程語言來處理JSON數(shù)據(jù)。而另一方面隨著REST歇盼、像MongoDB這樣的NoSQL技術或標準的廣泛使用舔痕,JSON也正成為一種被推薦的數(shù)據(jù)交互格式。

JSON是在2001年,由Douglas Crockford創(chuàng)建的伯复,并且被IETF(Internet Engineering Task Force)定義為RFC 4627標準慨代,詳請參考:http://tools.ietf.org/html/rfc4627。JSON的媒體類型被定義為 application/json啸如,而文件的后綴為.json侍匙。

JSON是什么

JSON是一種簡單數(shù)據(jù)格式,它有三種數(shù)據(jù)結構:

  • 鍵值對 —— Name/Value (Key/Value)
  • 對象 —— Object
  • 數(shù)組 —— Arrays

一個有效的JSON文檔需要被包含在一對花括號內(nèi)

{ JSON-Data }

請注意组底,有些開發(fā)社區(qū)或線上文檔直接將上面的JSON文檔稱為JSON字符串丈积,這兩者的意思是一樣的筐骇。

為什么使用JSON

JSON被認為是XML的很好替代者债鸡。因為JSON的可讀性非常好,而且它沒有像XML那樣包含很多冗余的元素標簽铛纬,這使得應用在使用JSON進行網(wǎng)絡傳輸以及進行解析處理的速度更快厌均,效率更高。

鍵值對 —— Name/Value

鍵值對是JSON中最基本的數(shù)據(jù)結構:

{
  “firstName”: “John”
}

在上面的例子中屬性"firstName"是用一對雙引號括起來的一個字符串告唆。而它的值"John"在這個例子中也是一個字符串棺弊,當然它還可以是其他類型,具體可參考后面數(shù)據(jù)類型的章節(jié)擒悬。在市面上很多的產(chǎn)品或技術聲稱他們使用的是JSON數(shù)據(jù)格式模她,但他們在定義屬性時,并沒有用雙引號將屬性名稱括起來懂牧,其實這是違反JSON定義標準的侈净。

對象 —— Object

一個JSON對象是包含了一組未排序鍵值對的集合。下面例子中的address就是一個JSON對象:

{
    “address” : {
        “l(fā)ine1” : “555 Main Street”,
        “city” : “Denver”,
        “stateOrProvince” : “CO”,
        “zipOrPostalCode” : “80202”,
        “country” : “USA”
    }
}

上面的例子中address對象包含了5個屬性僧凤,它們之間用,進行分割畜侦。

數(shù)組 —— Array

JSON中[]來包含數(shù)組元素,參考下面的例子:

{
    “people” : [
        { “firstName”: “John”, “l(fā)astName”: “Smith”, “age”: 35 },
        { “firstName”: “Jane”, “l(fā)astName”: “Smith”, “age”: 32 }
    ]
}

數(shù)據(jù)類型

JSON中的數(shù)值(鍵值對中的值)可以是以下任意一種:

  • Object
  • Array
  • String
  • Number
  • Boolean
  • null

Number

數(shù)值類型數(shù)據(jù)可以是整型也可以是雙精度的浮點型數(shù)據(jù)躯保。下面是一些示例:

“age”: 29
“cost”: 299.99
“temperature”: -10.5
“speed_of_light”: 1.23e11
“speed_of_light”: 1.23e+11
“speed_of_light”: 1.23E11
“speed_of_light”: 1.23E+11

上面的屬性(如age等)都是用雙引號括起來的字符串旋膳,而數(shù)值是不需要用雙引號括起來的。你可以在數(shù)值前加上-號來表示負數(shù)途事,也可以采用科學計數(shù)法验懊。但不能在數(shù)值前加0或使用16進制來表示一個數(shù)值。

Boolean

JSON中的Boolean值可以用true或false來表示尸变。

{
    “emailValidated” : true
}

Boolean值也不需要使用雙引號來修飾义图。

null

嚴格來說null并不是一個數(shù)據(jù)類型,但它非常重要振惰,它表示一個屬性或元素沒有值歌溉。因此請注意 ' ' 表示的是空字符串,而null表示的才是空值。

{
    “age” : null
}

代碼注釋

JSON不允許在JSON文檔或字符串中添加注釋痛垛。注釋功能最早在JSON中是存在的草慧,但開發(fā)者們錯誤地使用了它來輔助JSON數(shù)據(jù)的解析,當Douglas Crockford意識到這種不好的使用實踐后匙头,便取消了注釋功能漫谷,以保證JSON在不同計算平臺間作為交互數(shù)據(jù)格式的特性。

樣式

你可能已經(jīng)注意到了在之前的例子中蹂析,所有的屬性名稱都使用了駝峰式的命名規(guī)則舔示。這并不是JSON的一個標準要求,但這能夠幫助提高JSON文檔的可讀性电抚,因此作為一個事實標準在所有JSON應用中被使用惕稻。

語法

Douglas Crockford 在他的JSON網(wǎng)站http://www.json.org/中,給出了所有JSON語法語義的說明蝙叛。另外還有一個iOS App JSON Pro FREE可以用來通過示例學習或參考JSON俺祠。

JSON校驗

一個文本文檔或字符串必須遵守JSON的語法定義,才能被視作一個有效的JSON文檔借帘。JSON文檔是否有效非常重要蜘渣,因為它直接決定了,你的JSON數(shù)據(jù)能否在不同的應用中被正確地解析和使用肺然。JSONLint提供了一個可交互的Web版JSON校驗工具蔫缸,你只需要將你的JSON文檔粘貼進去,并點擊校驗按鈕际起,它便會自動進行校驗拾碌,并將問題顯示在下方。

在上面這個例子中加叁,這個JSON對象的city屬性沒有加上雙引號倦沧,導致校驗失敗。在返回的提示中它匕,顯示了“Expecting 'STRING', got 'undefined'”錯誤展融。

JSONLint也提供了一個可以在Chrome中直接使用的插件。

JSON數(shù)據(jù)模型

在應用中手工編寫JSON文檔豫柬,會很枯燥并容易出錯告希。為了防止這樣的惡錯誤 ,你可以使用JSONPad或JSON Editor Online這樣的工具烧给,它們能夠幫助你構建JSON邏輯模型(類似于UML),然后通過模型生成JSON文檔燕偶。

JSON Editor Online

[ JSON Editor Online] (http://jsoneditoronline.org/) 是一個在線JSON數(shù)據(jù)建模工具,他也提供了一個Chrome插件可以使用础嫡。

瀏覽器中的JSON

Firefox和Chrome都提供了一些很好的插件方便開發(fā)人員查看或處理JSON數(shù)據(jù)指么。

REST Client

Rest Client是Firefox中的一個擴展應用酝惧。他能夠幫助開發(fā)人員在瀏覽器中調(diào)試REST風格的Web Service。它最大的優(yōu)點是能將返回的JSON數(shù)據(jù)結果伯诬,以很好的格式顯示出來晚唇。

JSONView

JSONView是一個FireFox和Chrome上的插件,能夠很好地將JSON數(shù)據(jù)打印出來盗似,從而大大提高了JSON數(shù)據(jù)的可讀性哩陕。

JSON與AJAX

AJAX可能是使用JSON數(shù)據(jù)中最常見的場景了。下面的這段代碼示例赫舒,通過jQuery來調(diào)用一個REST風格的Web Service悍及,并處理返回的JSON對象。

$.getJSON(‘http://example/service/addresses/home/1’,
    function(data) {
        var address = JSON.parse(data);
        console.log(“Address Line 1 = “ + address.line1);
    }
);

在上面的這段代碼中接癌,$getJSON(這是一種jQuery中$.ajax()標準調(diào)用的一種縮寫形式)會發(fā)起一個HTTP GET 請求心赶,調(diào)用Web Service,之后在它的隱式回調(diào)函數(shù)中扔涧,獲取返回的data數(shù)據(jù)园担,并通過JSON.parse()方法將返回的數(shù)據(jù)轉(zhuǎn)換為JSON對象届谈。之后便可以像獲取普通屬性那樣(address.line1)獲取對象的屬性數(shù)值了枯夜。

JSON與JAVA

Jackson是JAVA中用來處理JSON的一個第三方庫。它很有名艰山,并且提供了一組非常好用的JSON API湖雹。下面就是它的一個例子:

import java.io.Writer;
import java.io.StringWriter;
import org.codehaus.jackson.map.ObjectMapper;

public class Address {
    private String line1;
    private String city;
    private String stateOrProvince;
    private String zipOrPostalCode;
    private String country;
    
    public Address() {}
    
    public String getLine1() {
        return line1;
    }

    public void setLine1(line1) {
        this.line1 = line1;
    }
    
    // Remaining getters and setters ...
}

Address addrOut = new Address();

// Call setters to populate addrOut …
ObjectMapper mapper = new ObjectMapper(); // Reuse this.
// Marshal Address object to JSON String.
Writer writer = new StringWriter();
mapper.writeValue(writer, addrOut);
System.out.println(writer.toString());

// Unmarshal Address object from JSON String.
String addrJsonStr =
“{“ +
    “\”address\” : {“ +
    “\”line1\” : \”555 Main Street\”,” +
    “\”city\” : \”Denver\”,”
    “\”stateOrProvince\” : \”CO\”,”
    “\”zipOrPostalCode\” : \”80202\”,” +
    “\”country\” : \”USA\”” +
    “}” +
“}”;

Address addrIn = mapper.readValue(addrJsonStr, Address.class);

除了Jackson之外,還有一些其他基于JAVA的第三方JSON API庫曙搬。

API Source
Google GSON http://code.google.com/p/google-json/
SOJO http://sojo.sourceforge.net/
org.json (by DouglasCrockford) http://www.json.org/java
json-lib http://sourceforge.net/projects/json-lib/
json-io http://code.google.com/p/json-io
jsontools http://jsontools.berlios.de/
jsonbeans http://code.google.com/p/jsonbeans/

JSON與RUBY

Ruby中也有很多與JSON相關的第三方庫摔吏,而JSON gem是Ruby自帶的,下面就是它的用法:

require ‘json’
class Address
    attr_accessor :line1, :city, :state_or_province,
                  :zip_or_postal_code, :country

    def initialize(line1=’’, city=’’, state_or_province=’’,
        zip_or_postal_code=’’, country=’’)
        @line1 = line1
        @city = city
        @state_or_province = state_or_province
        @zip_or_postal_code = zip_or_postal_code
        @country = country
    end
    
    def to_json
        to_hash.to_json
    end

    def from_json!(str)
        JSON.parse(str).each { |var, val| send(“#{var}=”, val) }
    end

    private

    def to_hash
        Hash[instance_variables.map { |var| [var[1..-1].to_sym,
            send(var[1..-1])] }]
    end
end

JSON gem的to_json方法將字符串或哈希轉(zhuǎn)換為JSON纵装。Address對象的to_json方法通過將它的成員轉(zhuǎn)換成哈希再對哈希值調(diào)用to_json征讲,最終將一個Address對象轉(zhuǎn)換為JSON格式。

addr1 = Address.new(‘555 Main Street’, ‘Denver’, ‘CO’, ‘80231’,
‘US’)
puts addr1.to_json
# Outputs the following …
{“l(fā)ine1”:”555 Main Street”,”city”:”Denver”,”state_or_
province”:”CO”,”zip_or_postal_code”:”80231”,”country”:”US”}

JSON gem的JSON.pase方法則將JSON字符串轉(zhuǎn)換為哈希橡娄。Address對象的from_jason!方法接收一個JSON字符串诗箍,然后調(diào)用JSON.parse來轉(zhuǎn)換哈希,然后再在對象上分別設置這些哈希的值挽唉。

json_addr = <<END
{
    “l(fā)ine1” : “999 Broadway”, “city” : “Anytown”,
    “state_or_province” : “CA”, “zip_or_postal_code” : “90210”,
    “country” : “USA”
}
END

addr2 = Address.new
addr2.from_json!(json_addr)

除了JSON gem之外滤祖,還有以下一些Ruby的JSON第三方庫

API Source
ActiveSupport JSON http://api.rubyonrails.org/classes/ActiveSupport/JSON.html
Yajl https://github.com/brianmario/yajl-ruby
Oj https://github.com/ohler55/oj

JSON與RUBY ON RAILS

Ruby on Rails也提供了將Ruby對象轉(zhuǎn)換為JSON的功能。下面的例子中的Controller使用了render方法將一個Ruby對象以JSON數(shù)據(jù)的格式進行輸出瓶籽。

Rails中的ApplicationController會負責對象與JSON數(shù)據(jù)之間的互相轉(zhuǎn)換 匠童。因此,不需要額外調(diào)用to_json方法塑顺。

JSON SCHEMA

JSON Schema用來定義JSON文檔的結構汤求,它可以被用來驗證和校驗發(fā)送或收到的JSON文檔是否有效和規(guī)范。JSON Schema本身也是用JSON格式編寫的,它的具體定義可以參考http://json-schema.org扬绪。

下面是JSON Schema的部分結構定義:

結構 描述
type 對象的數(shù)據(jù)類型寡喝,如Object,array,string,number 等
$schema 提供Schema版本的URI
required true/false
id 數(shù)據(jù)元素id
properties 數(shù)據(jù)元素的校驗屬性,包括最大值勒奇,最小值预鬓,枚舉等

下面是JSON Schema的一個示例

“type”: “object”,
“$schema”: “http://json-schema.org/draft-03/schema”,
“id”: “#”,
“required”: true,
“properties”: {
    “registrants”: {
        “type”: “array”,
        “id”: “registrants”,
        “required”: true,
        “items”: {
            “type”: “object”,
            “required”: false,
            “properties”: {
                “address”: {
                    “type”: “object”,
                    “id”: “address”,
                    “required”: true,
                    “properties”: {
                        “city”: {
                            “type”: “string”,
                            “id”: “city”,
                            “required”: true
                            },
                            “country”: {
                                “type”: “string”,
                                “id”: “country”,
                                “required”: false
                                },
                                “l(fā)ine1”: {
                                    “type”: “string”,
                                    “id”: “l(fā)ine1”,
                                    “required”: true
                                    },
                                    “l(fā)ine2”: {
                                        “type”: “string”,
                                        “id”: “l(fā)ine2”,
                                        “required”: false
                                        },
                                        “postalCode”: {
                                            “type”: “string”,
                                            “id”: “postalCode”,
                                            “required”: true
                                            },
                                            “premise”: {
                                                “type”: “string”,
                                                “id”: “premise”,
                                                “required”: true,
                                                “enum”: [
                                                    “work”,
                                                    “home”,
                                                    “other”
                                                ]
                                                },
                                                “stateOrProvince”: {
                                                    “type”: “string”,
                                                    “id”: “stateOrProvince”,
                                                    “required”: true
                                                }
                                            }
                                            },
                                            “firstName”: {
                                                “type”: “string”,
                                                “id”: “firstName”,
                                                “required”: true
                                                },
                                                “l(fā)astName”: {
                                                    “type”: “string”,
                                                    “id”: “l(fā)astName”,
                                                    “required”: true
                                                    },
                                                    “phoneNumber”: {
                                                        “type”: “object”,
                                                        “id”: “phoneNumber”,
                                                        “required”: true,
                                                        “properties”: {
                                                            “channel”: {
                                                                “type”: “string”,
                                                                “id”: “channel”,
                                                                “required”: true,
                                                                “enum”: [
                                                                    “cell”,
                                                                    “work”,
                                                                    “home”
                                                                ]
                                                                },
                                                                “number”: {
                                                                    “type”: “string”,
                                                                    “id”: “number”,
                                                                    “required”: true
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

在上面的Schema中對JSON對象做了以下約束:

  • registrants必須是一個數(shù)組對象
  • phoneNumber的channel必須是cell, work, fax, home中的一個
  • address的premise必須是home, work, other中的一個。

一個使用上述JSON Schema的Web Service可以解析和處理下面這個JSON文檔:

{
    "registrants": [
        {
            "firstName": "Fred",
            "lastName": "Smith",
            "phoneNumber": {
                "channel": "cell",
                "number": "303-555-1212"
                },
            "address": {
                    "premise": "home",
                    "line1": "555 Broadway NW",
                    "line2": "# 000",
                    "city": "Denver",
                    "stateOrProvince": "CO",
                    "postalCode": "88888",
                    "country": "USA"
                }
        }
    ]
}

JSON Schema 生成器

我們可以使用JSON Schema生成器來為一個有效的JSON文檔生成對應的Schema赊颠。你需要訪問(www.jsonschema.net)格二,然后按照以下步驟操作:

  • 將你的JSON文檔粘貼到右側(cè)文本框
  • 選擇JSON輸入選項
  • 點擊Generate Schema按鈕

JSON Schema 校驗器

我們可以用JSON Schema Validator來保證我們的JSON文檔時有效的。下面是針對不同開發(fā)語言的一些常見的JSON Schema 校驗器竣蹦。

校驗器 編程語言 項目地址
JSV JavaScript https://github.com/garycourt/JSV
Ruby JSON Schema Validator Ruby https://github.com/hoxworth/jsonschema
json-schemavalidator Java https://github.com/fge/json-schema-validator
php-json-schema(by MIT) PHP https://github.com/hasbridge/php-json-schema
JSON.Net .NET http://james.newtonking.com/projects/json-net.aspx

除了上面這些與編程語言相關的校驗器之外顶猜,你還可以直接使用在線的JSON Schema校驗器( http://json-schema-validator.herokuapp.com ),將Schema和JSON文檔粘貼到左側(cè)的文本框中痘括,然后點擊Validate按鈕长窄,校驗的結果就會顯示在屏幕右側(cè)。

總結

以上,我們已經(jīng)初步了解了JSON的核心定義和用法设哗,但對于JSON本身來說我們還只是了解了其中很小的一部分缘眶,還有許多與它相關的工具或技術可以使用。JSON作為一個數(shù)據(jù)標準嚣潜,它已經(jīng)逐步替代XML成為Internet上最受歡迎的交互數(shù)據(jù)格式。

簡書簽約作者:技匠椅贱,以上內(nèi)容歡迎大家分享到朋友圈/微博等懂算。如需轉(zhuǎn)載,請通過簡信聯(lián)系授權庇麦。謝謝大家计技!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市山橄,隨后出現(xiàn)的幾起案子垮媒,更是在濱河造成了極大的恐慌,老刑警劉巖驾胆,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涣澡,死亡現(xiàn)場離奇詭異,居然都是意外死亡丧诺,警方通過查閱死者的電腦和手機入桂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驳阎,“玉大人抗愁,你說我怎么就攤上這事馁蒂。” “怎么了蜘腌?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵沫屡,是天一觀的道長。 經(jīng)常有香客問我撮珠,道長沮脖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任芯急,我火速辦了婚禮勺届,結果婚禮上,老公的妹妹穿的比我還像新娘娶耍。我一直安慰自己免姿,他們只是感情好,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布榕酒。 她就那樣靜靜地躺著胚膊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪想鹰。 梳的紋絲不亂的頭發(fā)上紊婉,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音杖挣,去河邊找鬼肩榕。 笑死,一個胖子當著我的面吹牛惩妇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筐乳,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼歌殃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蝙云?” 一聲冷哼從身側(cè)響起氓皱,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勃刨,沒想到半個月后波材,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡身隐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年廷区,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贾铝。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡隙轻,死狀恐怖埠帕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玖绿,我是刑警寧澤敛瓷,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站斑匪,受9級特大地震影響呐籽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚀瘸,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一绝淡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苍姜,春花似錦牢酵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垫释,卻和暖如春丝格,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棵譬。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工显蝌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人订咸。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓曼尊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脏嚷。 傳聞我的和親對象是個殘疾皇子骆撇,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. JSON Schema關鍵字簡介 上篇文章中,我們通過一個簡單的JSON Schema的例子父叙,簡要地介紹了J...
    邱士超閱讀 5,613評論 0 16
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理神郊,服務發(fā)現(xiàn),斷路器趾唱,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 轉(zhuǎn)載: http://www.reibang.com/p/8b428e1d1564# JSON概覽 JSON(Ja...
    朝花夕拾不起來閱讀 2,645評論 1 37
  • 一縷清風一掩半臉涌乳,轉(zhuǎn)過了你的眼; 一微細雨一啟櫻唇甜癞,糊滿了誰歲月夕晓; 也曾守待歲月,握手張揚带欢; 也愿停駐風雨运授,對影一...
    求求女先生閱讀 185評論 0 0
  • 程序的局部變量存在于(堆棧)中烤惊,全局變量存在于(靜態(tài)區(qū) )中,動態(tài)申請數(shù)據(jù)存在于( 堆)中吁朦。 補充:堆和棧的概念 ...
    iOS_小勝閱讀 2,508評論 0 4