你不知道的JSON

RaHsu Lv1

JSON的历史

Douglas Crockford 是JSON的创造者,也是JavaScript:the good part的作者。

JSONJavaScript Object Notation)是一种由Douglas Crockford 构想和设计、轻量级的数据交换语言 ,该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管JSON是JavaScript 的一个子集,但JSON是独立于语言的文本格式 ,并且采用了类似于C语言 家族的一些习惯。

JSON格式是1999年《JavaScript Programming Language, Standard ECMA-262 3rd Edition》的子集合,所以可以在JavaScript eval()函数(javascript通过eval()调用解析器)读入。不过这并不代表JSON无法使用于其他语言,事实上几乎所有与网页开发相关的语言都有JSON函数库。

JSON是Douglas Crockford在2001年开始推广使用的数据格式,在2005年-2006年正式成为主流的数据格式,雅虎和谷歌就在那时候开始广泛地使用JSON格式。

什么是JSON( JavaScript Object Notation)

  • JSON是一种数据交换格式。

  • JSON独立于编程语言。

    JSON不局限于某项技术,本身非私有,且可移植。对于产生(序列化)和读取(反序列化)JSON 数据,所有的现代编程语言(Java、JavaScript、Ruby、C#、PHP、Python、Groovy等)和平台都提供了良好的支持。

    可以说,我们使用的是一种基于对象表示法的数据交换格式,JSON 表达数据的方式对通用的编程概念都很友好。

  • 为什么使用JSON:

    • 基于 JSON 的 RESTful API 的爆发式增长

    • JSON 基本数据结构的简洁性

      JSON 非常简洁,并且正在逐步替代 XML 成为互联网上主要的数据交换格式。它易于阅读,相关结构也很容易与软件开发人员所熟悉的概念对应起来,精简的数据类型也便于程序员理解,如数组、对象和名称 - 值对。

      由于节省了每个数据元素的开始标签与结束标签,JSON 格式的额外开销更少、更为紧凑,所以JSON 格式的文档一般比内容相同的 XML 文档小。从企业级应用的角度来看,与 XML 相比,JSON 文档在网络上的传输与处理更快,因此效率更高。

      如今 JSON 在配置文件领域也占有一席之地。后面会将与其他配置文件的区别。

JSON语法

JSON包含3种核心数据类型:

  • 名称-值对:由一个名称(数据属性)和一个值组成。

  • 对象:名称 - 值对的无序集合。

  • 数组:值的有序集合。

  • 键始终被双引号包围,当值是字符串时,必须使用双引号。

    JSON 中的名称 - 值对是一种对许多系统都十分友好的数据结构,而使用空格和特殊字符(即 a-z、0-9 除外的其他字符)忽略了可移植性。我们在第 1 章中将这一专业术语定义为“以一种双方系统都兼容的方式在平台间传递信息”。如果我们这么做的话,会直接降低 JSON 数据的可移植性;因此我们说,为了获得最大可移植性,应尽可能避免使用空格或特殊字符。

    JSON 中的名称 - 值对的名称如果被系统作为对象装入内存的话,将会成为“属性”。在部分系统中,属性名可以包含下划线( _ )或数字,但是大多数情况下最好是使用英文字母 AZ 或 az,在含有多个单词时,最好使用驼峰表示法。

    例子:”Lindsay’s animal”:”cat”

JSON数据类型

JSON中的数据类型:

在字符串中需要转义的字符:

  • 双引号
  • 反斜杠
  • / (正斜线)
  • \b (退格符)
  • \f (换页符)
  • \t (制表符)
  • \n (换行符)
  • \r (回车符)
  • \u 后面跟十六进制字符(如笑脸表情 \u263A )

JSON中的数字

  • 数字

    • 整型
    • 浮点数
    • 定点数 —— 计算机中采用的一种数的表示方法。参与运算的数的小数点位置固定不变 。

    数字需要注意:

    • 数值永远是十进制数(只能出现数字 0~9),不能以 0 开头。
    • 数值可以存在由小数点( . )开头的小数部分。
    • 数值可以是以 10 为底的指数,该指数由 e 或 E 来表示,其后跟正号表示正指数幂,跟
      负号则表示负指数幂。
    • 数值不支持八进制数和十六进制数。
    • 与 JavaScript 不同,数值不能是 NaN(Not a Number,用于表示非法数值),也不能是
      Infinity

没有注释

一言以蔽之,JSON 中没有注释。

根据 Crockford 在 Yahoo! JSON group 和 Google+ 上的说法,JSON 最开始是允许出现注释的,但之后不久就因为以下原因移除了注释。

  • Crockford 认为注释没有什么用处。

  • JSON 解析器在支持注释方面存在困难。

  • 出现了滥用注释的情况。Crockford 发现有些注释被用于解析指令,而这会彻底摧毁
    JSON 的互操作性。

  • 移除注释有利于 JSON 实现跨平台性,简化这方面的支持工作。

  • 没有注释意味着我们需要更语义化的命名,或者给要描述的对象添加一个描述字段。没有注释是JSON的一个相对于有注释数据格式在可读性方面的一个劣势。

    JSON风格指南

    google的一份风格指南。

    选择有意义的属性名

    • 属性名应该是具有定义语义的有意义的名称。
    • 属性名必须是驼峰式的,ASCII码字符串。
    • 首字符必须是字母,下划线(_)或美元符号($)。
    • 随后的其他字符可以是字母,数字,下划线(_)或美元符号($)。
    • 应该避免使用Javascript中的保留关键字(下文附有Javascript保留字清单)

    数组类型应该是复数属性名。其它属性名都应该是单数。

    数组通常包含多个条目,复数属性名就反映了这点。在下面这个保留名称中可以看到例子。属性名items是复数因为它描述的是一组对象。大多数的其它字段是单数。

    考虑移除空或null值

    如果一个属性是可选的或者包含空值或null值,考虑从JSON中去掉该属性,除非它的存在有很强的语义原因。

    枚举值应当以字符串的形式呈现

    随着APIs的发展,枚举值可能被添加,移除或者改变。将枚举值当作字符串可以使下游用户幽雅地处理枚举值的变更。

    通过选择新的属性名或将API版本化来避免命名冲突

    新的属性可在将来被添加进保留列表中。JSON中不存在命名空间。如果存在命名冲突,可通过选择新的属性名或者版本化来解决这个问题。

    JavaScript保留字应该避免在属性名中使用

    JSON结构和保留属性名

    https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md#json%E7%BB%93%E6%9E%84%E5%92%8C%E4%BF%9D%E7%95%99%E5%B1%9E%E6%80%A7%E5%90%8D

其他特性

  • 语法验证。

    工具:JSON Formatter & Validator 可视化工具,会展示树形结构。

       [JSON Editor Online](http://www.jsoneditoronline.org/)
    
       [JSONLint](http://jsonlint.com/) 
    

    以上这些都是语法验证工具。我们会在之后讨论另一种类型的验证——一致性验证。语法验证关注的是 JSON 的格式,而一致性验证关注的是其独特的数据结构。

  • JSON的媒体格式

    JSON 的 MIME 类型是 application/json 。

  • 序列化和反序列化。

    JSON从2009年的 ECMAScript 5 标准开始成为 JavaScript 原生类库的一部分。

    在之前使用eval()这个函数来执行序列化。

    使用 JSON.stringify() 和 JSON.parse() 进行 JavaScript 中的序列化 / 反序列化操作。

    其他的语言也有序列化和反序列化的库。

JSON作为配置文件

选择配置文件的考量:可读性,方便被编程语言/框架解析。

软件中经常会有配置文件或设置文件,它让我们可以不必重新编译就能修改设置。配置文件的格式有很多,有 INI ,yuml和 XML 等。

yuml和XML都是有注释的。

yuml除了支持JSON中的数据类型,还支持时间和日期这两种数据类型,相对于JSON,yaml的语法规则要稍微复杂一些,对于初学者来说,没有JSON那么好上手。

XML 能够包含更为复杂的数据,但是它不像 JSON 一样具有数据类型。

JSON和XML 还有另外一个很大的区别在于有效数据率。JSON作为数据包格式传输的时候具有更高的效率,这是因为JSON不像XML那样需要有严格的闭合标签,这就让有效数据量与总数据包比大大提升,从而减少同等数据流量的情况下,网络的传输压力

除了这些数据格式本身具有的优缺点外,是否能够很方便地被编程语言 / 框架解析也是一个很重要的考量因素。如果 JSON 解析器已经在你的应用中深度使用了,那么 JSON 可能是你配置文件的最佳选择。

JSON Schema 对数据进行验证(重点)语义校验

JSON Schema官网:http://json-schema.org/

JSON Schema is a vocabulary that allows you to annotate and validate JSON documents.

JSON Schema是一个词汇表,允许您注释和验证JSON文档。它也是一个JSON文件,本身遵守JSON规范。

json-schema 的用途越来越广泛,除了定义数据结构外,我们还可以使用 json-schema 验证数据格式和生成随机数据 。

它可以验证的内容有:

  • 值的数据类型是否正确?

    可以具体规定一个值是数字、字符串等类型。

  • 是否包含所需要的数据?

    可以具体规定哪些数据是需要的,哪些是不需要的。

  • 值的形式是不是我需要的?

    可以指定范围、最小值和最大值。

编写工具:https://jsonschema.net/

如何使用Schema

首先,需要在 JSON 第一个名称 - 值对中,声明其为一个 schema 文件。

第二个名称 - 值对应该是 JSON Schema 文件的标题.

在 JSON Schema 文件的第三个名称值对中,要定义需要在 JSON 中包含的属性。

为了在 JSON Schema 中实现这一逻辑,需要在 “$schema” 、 “title” 和”properties” 后面加上第四个名称 - 值对,它的名称是 “required” ,值为一个数组。数组中包含必填的字段。

非常重要的一点是,如果你的 JSON Schema 中不包含 “required” 名称 - 值对,那么将不会有必填项。一个没有任何名称 - 值对的空 JSON 对象也被认为是合法的。

本章提供的例子只是简介,是冰山一角。JSON Schema 还支持正则表达式(一种字符形式,比如电子邮件地址的格式)以及枚举类型(一个包含所有可能值的列表)。

用schema校验JSON

AJV号称是最快的JSON Schema验证器,我们看一下它的官网:可以看到这个下载次数非常高,说明使用的是非常广泛的。

我们还可以看到它的性能表现,这里号称是比第二名快50%。

它的特性:它支持04,06,07的草案标准,并且支持浏览器和nodejs,可以说是比较全面的验证器了。

工具

现在我要推荐一些工具给大家。

刚刚看了schema的语法,因为schema也是JSON文件,所以写起来还是比较麻烦的,特别是你的数据稍稍复杂一点就很费时间。这里推荐一个非常方便的一个工具:JSONSchema.net。你只需要填入你的示例数据,然后这个工具就会识别并自动生成schema,当然它做不到完全准确,它只能帮你完成70%的工作,还需要你去检查和完善,不过已经可以帮我们省下很多力气了。

接下来是生成测试数据,JSON-generator可以帮你生成你想要的测试数据,它提供一些工具函数来帮助你模拟出一些你想要的数据。

接下来要介绍一个非常好用的工具:JSON-server,来看一下的官网。

它的使用非常简单,也支持很多种动作。可以做过滤,分页,简单的排序啊,数据的切片啊等等功能,对于辅助我们平常的开发什么的还是够用的,这三个工具加在一起可以帮助我们提高很多效率哈。

在JSON中进行搜索

主要是给大家推荐几个工具,它们的使用方法都非常相似哈,这里以JSONPath为例介绍一下:

  • JSONPath
  • JSONPointer
  • jq

通过这张表我们可以看到它的查询能力还是比较全面的。

JSON与mysql

从MySQL 5.7.8 开始,MySQL支持原生的JSON格式,即有独立的json类型,用于存放 json格式的数据。

MySQL对支持JSON的做法是,在server层提供了一堆便于操作JSON的函数,至于存储,就是简单地将JSON编码成BLOB(binary large object),二进制大对象 ,然后交由存储引擎层进行处理,也就是说,MySQL 5.7的JSON支持与存储引擎没有关系,MyISAM 存储引擎也支持JSON 格式。

JSON 格式的数据并不是以string格式存储于数据库而是以内部的binary 格式,以便于快速的定位到json 格式中值

在插入和更新操作时MySQL会对JSON 类型做校验,已检查数据是否符合json格式,如果不符合则报错。

MySQL支持JSON以后,总是避免不了拿来与MongoDB进行一些比较。但是,MySQL对JSON的支持,至少有两点能够完胜MongoDB:

  1. 可以混合存储结构化数据和非结构化数据,同时拥有关系型数据库和非关系型数据库的优点
  2. 能够提供完整的事务支持

JSON与NoSQL

CouchDB

使用 JSON 文档存储数据的文档存储数据库——CouchDB。

无缝多主同步,可从大数据扩展到移动,具有直观的HTTP / JSON API,专为可靠性而设计。couchDB也可以作为一个数据库服务器来使用。

CouchDB(http://couchdb.apache.org/)是一种使用 JSON 文档存储数据的NoSQL 数据库。

Apache CouchDB是一个开源数据库,专注于易用性和成为”完全拥抱web的数据库”[1] 。它是一个使用JSON 作为存储格式,JavaScript 作为查询语言,MapReduce HTTP 作为API NoSQL 数据库。其中一个显著的功能就是多主复制。CouchDB的第一个版本发布在2005年,在2008年成为了Apache 的项目。

不同于关系型数据库 ,CouchDB没有将数据和关系存储在表格里。替代的,每个数据库是一个独立的文档集合。每一个文档维护其自己独立的数据和自包涵的schema。一个应用程序可能会访问多个数据库,比如其中一个位于用户的手机上,另一个位于在远程的服务器上。文档的元数据包含版本信息,让其能够合并可能因为数据库链接丢失导致的任何差异。

由于 CouchDB 使用文档来存储数据,因此当从数据库中查询一个账户时,得到的直接就是一个结构化的文档。没有必要进行重组。这样既高效又方便。

CouchDB 的另一个好处是有利于数据的变化。有些数据会随着时间而发生变化。当数据发生变化时,CouchDB无需修改表的结构。

MongoDB

MongoDB 是一种 NoSQL 数据库,允许开发人员以文档的形式存储数据。

MongoDB是一个文档数据库,具有您需要的可查询性和索引所需的可伸缩性和灵活性。

  • 关于BSON(Binary JSON,BSON)

    BSON 是 MongoDB 内部用于序列化 JSON 文档的一种二进制数据格式。

    bson对json做了一些对存储上的优化。

    json和bson的区别:

    • 更快的遍历速度

      对json格式来说,太大的json结构会导致数据遍历非常慢。在json中,要跳过一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据结构匹配,比如括号的匹配。而bson对json的一大改进就是,它会将json的每一个元素的长度存在元素的头部,这样你只需要读取到元素长度就能直接seek到指定的点上进行读取了。

    • 操作更简易

      对json来说,数据存储是无类型的,比如你要修改基本一个值,从9到10,由于从一个字符变成了两个,所以可能其后面的所有内容都需要往后移一位才可以。    而使用bson,你可以指定这个列为数字列,那么无论数字从9长到10还是100,我们都只是在存储数字的那一位上进行修改,不会导致数据总长变大。  当然,在mongoDB中,如果数字从整形增大到长整型,还是会导致数据总长变大的。

    • 增加了额外的数据类型

      json是一个很方便的数据交换格式,但是其类型比较有限。bson在其基础上增加了“byte array”数据类型。这使得二进制的存储不再需要先base64转换后再存成json,大大减少了计算开销和数据大小。当然,在有的时候,bson相对json来说也并没有空间上的优势,比如对{“field”:7},在json的存储上7只使用了一个字节,而如果用bson,那就是至少4个字节(32位)

  • 关于Schema

    MongoDB 是没有 Schema 的,这意味着数据库既不会校验数据,也不会在存储数据时依赖Schema。然而,应用程序对存储在每个文档中的数据还是会有数据结构上的预期,因为只有这样,应用程序才能放心地使用集合与文档。

    从MongoDB3.2开始,提供validator来对数据进行验证。

    在创建集合的时候指定一个验证器像这样。

    这个验证器也有自己的规范,这里就不一一介绍了

MessagePack

json作为数据交换格式,现在使用得越来越广泛,但是它还是有不少的弊端,MessagePack也是一个数据交换格式,它对针对JSON的一些问题做了一些优化。

图上这个json长度为27字节,但是为了表示这个数据结构,它用了9个字节(就是那些大括号、引号、冒号之类的,他们是白白多出来的)来表示那些额外添加的无意义数据。msgpack 的优化在图上展示的也比较清楚了,省去了特殊符号,用特定编码对各种类型进行定义,比如上图的A7,其中前四个bit A就是表示str的编码,而且它表示这个str的长度只用半个字节就可以表示了,也就是后面的7,因此A7的意思就是表示后面是一个7字节长度的string。

但是这个格式的可读性和可编辑性就比较差了。

核心压缩方式可参看官方说明messagepack specification
概括来讲就是:

  1. true、false 之类的:这些太简单了,直接给1个字节,(0xc3 表示true,0xc2表示false)
  2. 不用表示长度的:就是数字之类的,他们天然是定长的,是用一个字节表示后面的内容是什么,比如用(0xcc 表示这后面,是个uint 8,用oxcd表示后面是个uint 16,用 0xca 表示后面的是个float 32)。对于数字做了进一步的压缩处理,根据大小选择用更少的字节进行存储,比如一个长度<256的int,完全可以用一个字节表示。
  3. 不定长的:比如字符串、数组、二进制数据(bin类型),类型后面加 1~4个字节,用来存字符串的长度,如果是字符串长度是256以内的,只需要1个字节,MessagePack能存的最长的字符串,是(2^32 -1 ) 最长的4G的字符串大小。
  4. 高级结构:MAP结构,就是k-v 结构的数据,和数组差不多,加1~4个字节表示后面有多少个项
  5. Ext结构:表示特定的小单元数据。也就是用户自定义数据结构。

protocol buffer

Google Protocol Buffers 简称 Protobuf,它提供了一种灵活、高效、自动序列化结构数据的机制,可以联想 XML,但是比 XML 更小、更快、更简单。仅需要自定义一次你所需的数据格式,然后用户就可以使用 Protobuf 编译器自动生成各种语言的源码,方便的读写用户自定义的格式化的数据。与语言无关,与平台无关,还可以在不破坏原数据格式的基础上,依据老的数据格式,更新现有的数据格式。

Protobuf 的特点简单总结如下几点:

  • 作用与 XML、json 类似,但它是二进制格式,性能好、效率高
  • 代码生成机制,易于使用
  • 解析速度快
  • 支持多种语言
  • 向后兼容、向前兼容
  • 缺点:可读性差

目前,Protobuf 提供了两个大版本: 2.x 版本和 3.x 版本。 2.x 版本最新的版本是 2.6.1,支持 C++、Java 和 Python 三种语言的API。 3.x 版本最新的版本是 3.0.0-beta-1,支持 C++、Java、Python、Ruby、JavaNano、Objective-x 和 C# 这几种语言的 API。

  • Title: 你不知道的JSON
  • Author: RaHsu
  • Created at : 2018-05-06 20:46:25
  • Updated at : 2024-09-17 16:40:29
  • Link: http://www.rahsu.com/Tech/你不知道的JSON/
  • License: All Rights Reserved © RaHsu