蚊章汇 - XML
type: channel
link: https://linuxcn.bwsl.wang/tag/XML/
items: 使用 Java 解析 XML 文件
items: 在命令行中使用 XMLStarlet 来解析 XML
items: 什么是 XML？
items: 如何使用 Protobuf 做数据交换
items: JSON、XML、TOML、CSON、YAML 大比拼
items: XML 与 JSON 优劣对比
items: JSON 的兴起与崛起
items: C++ 程序员 Protocol Buffers 基础指南

使用 Java 解析 XML 文件
type: item
date: 2022-03-22T17:16:00+08:00
description: 在你使用 Java 编写软件时实现持久化配置。当你编写一个应用时，你通常都会希望用户能够定制化他们和应用交互的方式，以及应用与系统进行交互的方式。这种方式通常被称为 “ 偏好 preference ” 或者 “ 设置 setting ”，它们被保存在一个 “偏好文件” 或者 “配置文件” 中，有时也直接简称为 “ 配置 config ”。配置文件可以有很多种格式，包括 INI、JSON、YAML 和 XML。每一种编程语言解析这些格式的方式都不同。本文主要讨论，当你在使用 Java 编程语言 来编写软件时，实现持久化配置的方式。选择一个格式编写配置文件是一件相当复杂的事情。我曾经试过把配置项使用逗号分隔保存在一个文本文件里，也试过把配置项保存在非常详细的 YAML 和 XML 中。对于配置文件来说，最重要是要有一致性和规律性，它们使你可以简单快速地编写代码，从配置文件中解析出数据；同时，当用户决定要做出修改时，很方便地保存和更新配置。目前有 几种流行的配置文件格式。对于大多数常见的配置文件格式，Java 都有对应的 库 library 。在本文中，我将使用 XML 格式。对于一些项目，你可能会选择使用 XML，因为它的一个突出特点是能够为包含的数据提供大量相关的元数据，而在另外一些项目中，你可能会因为 XML 的冗长而不选择它。在 Java 中使用 XML 是非常容易的，因为它默认包含了许多健壮的 XML 库。XML 基础讨论 XML 可是一个大话题。我有一本关于 XML 的书，它有超过 700 页的内容。幸运的是，使用 XML 并不需要非常了解它的诸多特性。就像 HTML 一样，XML 是一个带有开始和结束标记的分层标记语言，每一个标记（标签）内可以包含零个或更多数据。下面是一个 XML 的简单示例片段：<xml> <node> <element>Penguin</element> </node> </xml> 在这个 自我描述的 self-descriptive 例子中，XML 解析器使用了以下几个概念： 文档 Document ：<xml> 标签标志着一个 文档 的开始，</xml> 标签标志着这个文档的结束。 节点 Node ：<node> 标签代表了一个 节点。 元素 Element ：<element>Penguin</element> 中，从开头的 < 到最后的 > 表示了一个 元素。 内容 Content ： 在 <element> 元素里，字符串 Penguin 就是 内容。不管你信不信，只要了解了以上几个概念，你就可以开始编写、解析 XML 文件了。创建一个示例配置文件要学习如何解析 XML 文件，只需要一个极简的示例文件就够了。假设现在有一个配置文件，里面保存的是关于一个图形界面窗口的属性：<xml> <window> <theme>Dark</theme> <fullscreen>0</fullscreen> <icons>Tango</icons> </window> </xml> 创建一个名为 ~/.config/DemoXMLParser 的目录：$ mkdir ~/.config/DemoXMLParser 在 Linux 中，~/.config 目录是存放配置文件的默认位置，这是在 自由桌面工作组 的规范中定义的。如果你正在使用一个不遵守 自由桌面工作组 Freedesktop 标准的操作系统，你也仍然可以使用这个目录，只不过你需要自己创建这些目录了。 复制 XML 的示例配置文件，粘贴并保存为 ~/.config/DemoXMLParser/myconfig.xml 文件。使用 Java 解析 XML如果你是 Java 的初学者，你可以先阅读我写的 面向 Java 入门开发者的 7 个小技巧。一旦你对 Java 比较熟悉了，打开你最喜爱的集成开发工具（IDE），创建一个新工程。我会把我的新工程命名为 myConfigParser。刚开始先不要太关注依赖导入和异常捕获这些，你可以先尝试用 javax 和 java.io 包里的标准 Java 扩展来实例化一个解析器。如果你使用了 IDE，它会提示你导入合适的依赖。如果没有，你也可以在文章稍后的部分找到完整的代码，里面就有完整的依赖列表。Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser"); File configFile = new File(configPath.toString(), "myconfig.xml"); DocumentBuilderFactory factory = DocumentBuilderFac…

在命令行中使用 XMLStarlet 来解析 XML
type: item
date: 2021-07-29T17:13:00+08:00
description: 借助终端上的 XML 工具包 XMLStarlet，你就是 XML 之星。学习解析 XML 通常被认为是一件复杂的事情，但它不一定是这样。XML 是高度严格结构化的，所以也是相对来说可预测的。也有许多其他工具可以帮助你使这项工作易于管理。我最喜欢的 XML 实用程序之一是 XMLStarlet，这是一个用于终端的 XML 工具包，借助这个 XML 工具包，你可以验证、解析、编辑、格式化和转换 XML 数据。XMLStarLet 是个相对较小的命令，但浏览 XML 却充满潜力，因此本文演示了如何使用它来查询 XML 数据。安装XMLStarLet 默认安装在 CentOS、Fedora，和许多其他现代 Linux 发行版上，所以你可以打开终端，输入 xmlstarlet 来访问它。如果 XMLStarLet 还没有被安装，你的操作系统则会为你安装它。或者，你可以用包管理器安装 xmlstarlet：$ sudo dnf install xmlstarlet 在 macOS 上，可以使用 MacPorts 或 Homebrew。在 Windows 上，可以使用 Chocolatey。如果都失败了，你可以从 Sourceforge 上的源代码 手动安装它。用 XMLStarlet 解析 XML有许多工具可以帮助解析和转换 XML 数据，包括允许你 编写自己的解析器 的软件库，和复杂的命令，如 fop 和 xsltproc。不过有时你不需要处理 XML 数据；你只需要一个方便的方法从 XML 数据中来提取、更新或验证重要数据。对于随手的 XML 交互，我使用 xmlstarlet，这是常见的处理 XML任务的一个典型的“瑞士军刀”式应用。通过运行 --help 命令，你可以看到它提供哪些选项：$ xmlstarlet --help Usage: xmlstarlet [<options>] <command> [<cmd-options>] where <command> is one of: ed (or edit) - Edit/Update XML document(s) sel (or select) - Select data or query XML document(s) (XPATH, etc) tr (or transform) - Transform XML document(s) using XSLT val (or validate) - Validate XML document(s) (well-formed/DTD/XSD/RelaxNG) fo (or format) - Format XML document(s) el (or elements) - Display element structure of XML document c14n (or canonic) - XML canonicalization ls (or list) - List directory as XML [...] 你可以通过在这些子命令的末尾附加 -help 来获得进一步的帮助：$ xmlstarlet sel --help -Q or --quiet - do not write anything to standard output. -C or --comp - display generated XSLT -R or --root - print root element <xsl-select> -T or --text - output is text (default is XML) -I or --indent - indent output [...] 用 sel 命令选择数据可以使用 xmlstarlet select（简称 sel）命令查看 XML 格式的数据。下面是一个简单的 XML 文档：<?xml version="1.0" encoding="UTF-8" standalone="no"?> <xml> <os> <linux> <distribution> <name>Fedora</name> <release>7</release> <codename>Moonshine</codename> <spins> <name>Live</name> <name>Fedora</name> <name>Everything</name> </spins> </distribution> <distribution> <name>Fedora Core</name> <release>6</release> <codename>Zod</codename> <spins></spins>…

什么是 XML？
type: item
date: 2021-07-28T16:26:44+08:00
description: 了解一下 XML 吧，它是一种严格但灵活的标记语言，无论是在文档还是图像方面应用都十分广泛。XML 是一种分层的标记语言。它使用打开和关闭标签来定义数据，它常用来存储和交换数据，而且由于它极大的灵活性，不论是在 文档 还是 图像 中都用的非常多。这里是一个 XML 文档的例子：<xml> <os> <linux> <distribution> <name>Fedora</name> <release>8</release> <codename>Werewolf</codename> </distribution> <distribution> <name>Slackware</name> <release>12.1</release> <mascot> <official>Tux</official> <unofficial>Bob Dobbs</unofficial> </mascot> </distribution> </linux> </os> </xml> 阅读这个示例 XML，你可能会发现这个 XML 的格式具有直观的特性。 无论你是否熟悉这个文档的主题，你都可能理解本文档中的数据。 这部分原因是因为 XML 被认为是冗长的。 它使用了很多标签，标签可以有很长的描述性名称，并且数据以分层的方式排序，这有助于解释数据之间的关系。 你可能从这个示例中了解到 Fedora 发行版和 Slackware 发行版是两个不同且不相关的 Linux 发行版，因为每个实例都“包含”在自己独立的 <distribution> 标签中。XML 也非常灵活。 与 HTML 不同，它没有预定义的标签列表。 你可以自由创建你需要表示任何数据结构的标签。XML 的组成数据的存在为了读取，当计算机“读取”数据时，该过程称为 解析。 再次使用示例 XML 数据，以下是大多数 XML 解析器认为重要的术语。文档：<xml> 标签标记文档的开始， </xml> 标签标记文档的结束。节点：<os>、<distribution>、<mascot> 这些都是节点，在解析术语中，节点是包含其他标签的标签。元素：像 <name>Fedora</name> 和 <official>Tux</official> 这些都是元素。从第一个<开始，到最后一个 > 结束是一个元素。内容：在两个元素标签之间的数据被称之为内容，在第一个 <name> 标签中，Fedora 字符串就是一个内容。XML 模式XML 文档中的标签和标签继承性称为 模式。一些模式是随意组成的（例如，本文中的示例 XML 代码纯粹是即兴创作的），而其他模式则由标准组织严格定义。 例如，可缩放矢量图形（SVG）模式 由 W3C 定义，而 DocBook 模式 由 Norman Walsh 定义。模式强制执行一致性。 最基本的模式通常也是最严格的。 在我的示例 XML 代码中，将发行版名称放在 <mascot> 节点中是没有意义的，因为文档的隐含模式清楚地表明 mascot 必须是发行版的“子”元素。数据对象模型（DOM）如果你必须不断地描述标签和位置（例如，“系统部分中的 Linux 部分中第二个发行版标签的名称标签”），那么谈论 XML 会让人感到困惑，因此解析器使用文档对象模型（DOM）的概念来表示 XML 数据。 DOM 将 XML 数据放入一种“家谱”结构中，从根元素（在我的示例 XML 中，即 os 标记）开始并包括路径上的每个标记。这种相同的 XML 数据结构可以表示为路径，就像 Linux 系统中的文件或互联网上网页的位置一样。 例如，<mascot> 标签的路径可以表示为 //os/linux/distribution/slackware/mascot。两个 <distribution> 标签可以被表示为 //os/linux/distribution ，因为这里有两个发行版的节点，因此一个解析器可以直接将两个节点的内容载入到一个数组中，可以进行查询。严格的 XMLXML 也以严格而著称。 这意味着大多数应用程序被设计为在遇到 XML 错误时就会故意失败。 这听起来可能有问题，但这是开发人员最欣赏 XML 的事情之一，因为当应用程序试图猜测如何解决错误时，可能会发生不可预测的事情。 例如，在 HTML 定义明确之前，大多数 Web 浏览器都包含“怪癖模式”，因此当人们试图查看糟糕的 HTML 代码时，Web 浏览器却可以加载作者可能想要的内容。 结果非常难以预测，尤其是当一个浏览器的猜测与另一个浏览器不同时。XML 通过在出现故意错误时失败而不允许这样做。 这让作者可以修复错误，直到它们生成有效的 XML。 因为 XML 是良好定义的，所以有许多应用程序的验证器插件以及像 xmllint …

如何使用 Protobuf 做数据交换
type: item
date: 2019-11-22T15:59:06+08:00
description: 在以不同语言编写并在不同平台上运行的应用程序之间交换数据时，Protobuf 编码可提高效率。 协议缓冲区 Protocol Buffers （Protobufs）像 XML 和 JSON 一样，可以让用不同语言编写并在不同平台上运行的应用程序交换数据。例如，用 Go 编写的发送程序可以在 Protobuf 中对以 Go 表示的销售订单数据进行编码，然后用 Java 编写的接收方可以对它进行解码，以获取所接收订单数据的 Java 表示方式。这是在网络连接上的结构示意图：Go 销售订单 —> Pbuf 编码 —> 网络 —> Pbuf 界面 —> Java 销售订单与 XML 和 JSON 相比，Protobuf 编码是二进制而不是文本，这会使调试复杂化。但是，正如本文中的代码示例所确认的那样，Protobuf 编码在大小上比 XML 或 JSON 编码要有效得多。Protobuf 以另一种方式提供了这种有效性。在实现级别，Protobuf 和其他编码系统对结构化数据进行 序列化 serialize 和 反序列化 deserialize 。序列化将特定语言的数据结构转换为字节流，反序列化是将字节流转换回特定语言的数据结构的逆运算。序列化和反序列化可能成为数据交换的瓶颈，因为这些操作会占用大量 CPU。高效的序列化和反序列化是 Protobuf 的另一个设计目标。最近的编码技术，例如 Protobuf 和 FlatBuffers，源自 1990 年代初期的 DCE/RPC（ 分布式计算环境/远程过程调用 Distributed Computing Environment/Remote Procedure Call ）计划。与 DCE/RPC 一样，Protobuf 在数据交换中为 IDL（接口定义语言）和编码层做出了贡献。本文将着眼于这两层，然后提供 Go 和 Java 中的代码示例以充实 Protobuf 的细节，并表明 Protobuf 是易于使用的。Protobuf 作为一个 IDL 和编码层像 Protobuf 一样，DCE/RPC 被设计为与语言和平台无关。适当的库和实用程序允许任何语言和平台用于 DCE/RPC 领域。此外，DCE/RPC 体系结构非常优雅。IDL 文档是一侧的远程过程与另一侧的调用者之间的协定。Protobuf 也是以 IDL 文档为中心的。IDL 文档是文本，在 DCE/RPC 中，使用基本 C 语法以及元数据的语法扩展（方括号）和一些新的关键字，例如 interface。这是一个例子：[uuid (2d6ead46-05e3-11ca-7dd1-426909beabcd), version(1.0)] interface echo { const long int ECHO_SIZE = 512; void echo( [in] handle_t h, [in, string] idl_char from_client[ ], [out, string] idl_char from_service[ECHO_SIZE] ); }该 IDL 文档声明了一个名为 echo 的过程，该过程带有三个参数：类型为 handle_t（实现指针）和 idl_char（ASCII 字符数组）的 [in] 参数被传递给远程过程，而 [out] 参数（也是一个字符串）从该过程中传回。在此示例中，echo 过程不会显式返回值（echo 左侧的 void），但也可以返回值。返回值，以及一个或多个 [out] 参数，允许远程过程任意返回许多值。下一节将介绍 Protobuf IDL，它的语法不同，但同样用作数据交换中的协定。DCE/RPC 和 Protobuf 中的 IDL 文档是创建用于交换数据的基础结构代码的实用程序的输入：IDL 文档 —> DCE/PRC 或 Protobuf 实用程序 —> 数据交换的支持代码作为相对简单的文本，IDL 是同样便于人类阅读的关于数据交换细节的文档（特别是交换的数据项的数量和每个项的数据类型）。Protobuf 可用于现代 RPC 系统，例如 gRPC；但是 Protobuf 本身仅提供 IDL 层和编码层，用于从发送者传递到接收者的消息。与原本的 DCE/RPC 一样，Protobuf 编码是二进制的，但效率更高。目前，XML 和 JSON 编码仍在通过 Web 服务等技术进行的数据交换中占主导地位，这些技术利用 Web 服务器、传输协议（例如 TCP、HTTP）以及标准库和实用程序等原有的基础设施来处理 XML 和 JSON 文档。 此外，各种类型的数据库系统可以存储 XML 和 JSON 文档，甚至旧式关系型系统也可以轻松生成查询结果的 XML 编码。现在，每种通用编程语言都具…

JSON、XML、TOML、CSON、YAML 大比拼
type: item
date: 2019-03-29T09:15:04+08:00
description: 一段超级严肃的关于样本序列化的集合、子集和超集的文字我是一名开发者，我读代码，我写代码，我写会写代码的代码，我写会写出供其它代码读的代码的代码。这些都非常火星语，但是有其美妙之处。然而，最后一点，写会写出供其它代码读的代码的代码，可以很快变得比这段文字更费解。有很多方法可以做到这一点。一种不那么复杂而且开发者社区最爱的方式是数据序列化。对于那些不了解我刚刚抛给你的时髦词的人，数据序列化是从一个系统获取一些信息，将其转换为其它系统可以读取的格式，然后将其传递给其它系统的过程。虽然数据序列化格式多到可以埋葬哈利法塔，但它们大多分为两类：易于人类读写，易于机器读写。很难两全其美，因为人类喜欢让我们更具表现力的松散类型和灵活格式标准，而机器倾向于被确切告知一切事情而没有二义性和细节缺失，并且认为“严格规范”才是它们最爱的口味。由于我是一名 web 开发者，而且我们是一个创建网站的机构，我们将坚持使用 web 系统可以理解或不需要太多努力就能理解的特殊格式，而且对人类可读性特别有用的格式：XML、JSON、TOML、CSON 以及 YAML。每个都有各自的优缺点和适当的用例场景。事实最先回到互联网的早期，一些非常聪明的家伙决定整合一种让每个系统都能理解的标准语言，并创造性地将其命名为 标准通用标记语言 Standard Generalized Markup Language （简称 SGML）。SGML 非常灵活，发布者也很好地定义了它。它成为了 XML、SVG 和 HTML 等语言之父。所有这三个都符合 SGML 规范，可是它们都是规则更严格、灵活性更少的子集。最终，人们开始看到非常小、简洁、易读且易于生成的数据的好处，这些数据可以在系统之间以编程的方式共享，而开销很小。大约在那个时候，JSON 诞生了并且能够满足所有的需求。而另一方面，其它语言也开始出现以处理更多的专业用例，如 CSON，TOML 和 YAML。XML：不行了原本，XML 语言非常灵活且易于编写，但它的缺点是冗长，人类难以阅读、计算机非常难以读取，并且有很多语法对于传达信息并不是完全必要的。今天，它在 web 上的数据序列化的用途已经消失了。除非你在编写 HTML 或者 SVG，否则你不太能在许多其它地方看到 XML。一些过时的系统今天仍在使用它，但是用它传递数据往往太重了。我已经可以听到 XML 老爷爷开始在它们的石碑上乱写为什么 XML 是了不起的，所以我将提供一个小小的补充：XML 可以很容易地由系统和人读写。然而，真的，我的意思是荒谬的，很难创建一个可以规范的读取它的系统。这是一个简单美观的 XML 示例：<book id="bk101"> <author>Gambardella, Matthew</author> XML Developer's Guide <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book>太棒了。易于阅读、理解、写入，也容易编码一个可以读写它的系统。但请考虑这个例子：<!DOCTYPE r [ <!ENTITY y "a]>b"> ]> <r> " /> [a>b b <a <?x <!-- ?> c --> d </r>这上面是 100% 有效的 XML。几乎不可能阅读、理解或推理。编写可以使用和理解这个的代码将花费至少 36 根头发和 248 磅咖啡渣。我们没有那么多时间或咖啡，而且我们大多数老程序员们现在都是秃头。所以，让它活在我们的记忆里，就像 css hacks、IE 6 浏览器 和真空管一样好了。JSON：并列聚会好吧，我们都同意，XML = 差劲。那么，好的替代品是什么？ JavaScript 对象表示法 JavaScript Object Notation ，简称 JSON。JSON（读起来像 Jason 这个名字） 是 Brendan Eich 发明的，并且得到了伟大而强力的 JavaScript 意见领袖 Douglas Crockford 的推广。它现在几乎用在任何地方。这种格式很容易由人和机器编写，按规范中的严格规则解析也相当容易，并且灵活 —— 允许深层嵌套数据，支持所有的原始数据类型，及将集合解释为数组或对象。JSON 成为了将数据从一个系统传输到另一个系统的事实标准。几乎所有语言都有内置读写它的功能。JSON语法很简单。方括号表示数组，花括号表示记录，由冒号分隔的两个值分别表示属性或“键”（在左边）、值（在右边）。所有键必…

XML 与 JSON 优劣对比
type: item
date: 2019-02-07T06:39:59+08:00
description: 简介XML 和 JSON 是现今互联网中最常用的两种数据交换格式。XML 格式由 W3C 于 1996 年提出。JSON 格式由 Douglas Crockford 于 2002 年提出。虽然这两种格式的设计目标并不相同，但它们常常用于同一个任务，也就是数据交换中。XML 和 JSON 的文档都很完善（RFC 7159、RFC 4825），且都同时具有 人类可读性 human-readable 和 机器可读性 machine-readable 。这两种格式并没有哪一个比另一个更强，只是各自适用的领域不用。（LCTT 译注：W3C 是互联网联盟，制定了各种 Web 相关的标准，如 HTML、CSS 等。Douglas Crockford 除了制定了 JSON 格式，还致力于改进 JavaScript，开发了 JavaScript 相关工具 JSLint 和 JSMin）XML 的优点XML 与 JSON 相比有很多优点。二者间最大的不同在于 XML 可以通过在标签中添加属性这一简单的方法来存储 元数据 metadata 。而使用 JSON 时需要创建一个对象，把元数据当作对象的成员来存储。虽然二者都能达到存储元数据的目的，但在这一情况下 XML 往往是更好的选择，因为 JSON 的表达形式会让客户端程序开发人员误以为要将数据转换成一个对象。举个例子，如果你的 C++ 程序需要使用 JSON 格式发送一个附带元数据的整型数据，需要创建一个对象，用对象中的一个 名称/值对 name/value pair 来记录整型数据的值，再为每一个附带的属性添加一个名称/值对。接收到这个 JSON 的程序在读取后很可能把它当成一个对象，可事实并不是这样。虽然这是使用 JSON 传递元数据的一种变通方法，但他违背了 JSON 的核心理念：“ JSON 的结构与常规的程序语言中的结构相对应，而无需修改。 JSON’s structures look like conventional programming language structures. No restructuring is necessary. ” 1 虽然稍后我会说这也是 XML 的一个缺点，但 XML 中对命名冲突、 前缀 prefix 的处理机制赋予了它 JSON 所不具备的能力。程序员们可以通过前缀来把统一名称给予两个不同的实体。 2 当不同的实体在客户端中使用的名称相同时，这一特性会非常有用。XML 的另一个优势在于大多数的浏览器可以把它以 具有高可读性和强组织性的方式 highly readable and organized way 展现给用户。XML 的树形结构让它易于结构化，浏览器也让用户可以自行展开或折叠树中的元素，这简直就是调试的福音。XML 对比 JSON 有一个很重要的优势就是它可以记录 混合内容 mixed content 。例如在 XML 中处理包含结构化标记的字符串时，程序员们只要把带有标记的文本放在一个标签内就可以了。可因为 JSON 只包含数据，没有用于指明标签的简单方式，虽然可以使用处理元数据的解决方法，但这总有点滥用之嫌。JSON 的优点JSON 自身也有很多优点。其中最显而易见的一点就是 JSON 比 XML 简洁得多。因为 XML 中需要打开和关闭标签，而 JSON 使用名称/值对表示数据，使用简单的 { 和 } 来标记对象，[ 和 ] 来标记数组，, 来表示数据的分隔，: 表示名称和值的分隔。就算是使用 gzip 压缩，JSON 还是比 XML 要小，而且耗时更少。 3 正如 Sumaray 和 Makki 在实验中指出的那样，JSON 在很多方面都比 XML 更具优势，得出同样结果的还有 Nurseitov、Paulson、Reynolds 和 Izurieta。首先，由于 JSON 文件天生的简洁性，与包含相同信息的 XML 相比，JSON 总是更小，这意味着更快的传输和处理速度。第二，在不考虑大小的情况下，两组研究 4 5 表明使用 JSON 执行序列化和反序列化的速度显著优于使用 XML。第三，后续的研究指出 JSON 的处理在 CPU 资源的使用上也优于 XML。研究人员发现 JSON 在总体上使用的资源更少，其中更多的 CPU 资源消耗在用户空间，系统空间消耗的 CPU 资源较少。这一实验是在 RedHat 的设备上进行的，RedHat 表示更倾向于在用户空间使用 CPU 资源。 6 不出意外，Sumaray 和 Makki 在研究里还说明了在移动设备上 JSON 的性能也优于 XML。 7 这是有道理的，因为 JSON 消耗的资源更少，而移动设备的性能也更弱。JSON 的另一个优点在于其对对象和数组的表述和 宿主语言 host…

JSON 的兴起与崛起
type: item
date: 2019-01-14T19:50:00+08:00
description: JSON 已经占领了全世界。当今，任何两个应用程序彼此通过互联网通信时，可以打赌它们在使用 JSON。它已被所有大型企业所采用：十大最受欢迎的 web API 接口列表中（主要由 Google、Facebook 和 Twitter 提供），仅仅只有一个 API 接口是以 XML 的格式开放数据的。 1 这个列表中的 Twitter API 为此做了一个鲜活的注脚：其对 XML 格式的支持到 2013 年结束，其时发布的新版本的 API 取消 XML 格式，转而仅使用 JSON。JSON 也在程序编码级别和文件存储上被广泛采用：在 Stack Overflow（LCTT 译注：一个面向程序员的问答网站）上，现在更多的是关于 JSON 的问题，而不是其他的数据交换格式。 2 XML 仍然在很多地方存在。网络上它被用于 SVG 和 RSS / Atom 信息流。Android 开发者想要获得用户权限许可时，需要在其 APP 的 manifest 文件中声明 —— 此文件是 XML 格式的。XML 的替代品也不仅仅只有 JSON，现在有很多人在使用 YAML 或 Google 的 Protocol Buffers 等技术，但这些技术的受欢迎程度远不如 JSON。目前来看，JSON 是应用程序在网络之间通信的首选协议格式。考虑到自 2005 年来 Web 编程世界就垂涎于 “异步 JavaScript 和 XML” 而非 “异步 JavaScript 和 JSON” 的技术潜力，你可以发现 JSON 的主导地位是如此的让人惊讶。当然了，这可能与这两种通信格式的受欢迎程度无关，而仅反映出缩写 “AJAX” 似乎比 “AJAJ” 更具吸引力。但是，即使在 2005 年有些人（实际上没有太多人）已经用 JSON 来取代 XML 了，我们不禁要问 XML 的噩运来的如此之快，以至于短短十来年，“异步 JavaScript 和 XML” 这个名称就成为一个很讽刺的误称。那这十来年发生了什么？JSON 怎么会在那么多应用程序中取代了 XML？现在被全世界工程师和系统所使用、依赖的这种数据格式是谁提出的？JSON 之诞生2001 年 4 月，首个 JSON 格式的消息被发送出来。此消息是从旧金山湾区某车库的一台计算机发出的，这是计算机历史上重要的的时刻。Douglas Crockford 和 Chip Morningstar 是一家名为 State Software 的技术咨询公司的联合创始人，他们当时聚集在 Morningstar 的车库里测试某个想法，发出了此消息。在 “AJAX” 这个术语被创造之前，Crockford 和 Morningstar 就已经在尝试构建好用的 AJAX 应用程序了，可是浏览器对其兼容性不好。他们想要在初始页面加载后就将数据传递给应用程序，但其目标要针对所有的浏览器，这就实现不了。这在今天看来不太可信，但是要记得 2001 年的时候 Internet Explorer（IE）代表了网页浏览器的最前沿技术产品。早在 1999 年的时候，Internet Explorer 5 就支持了原始形式的 XMLHttpRequest，开发者可以使用名为 ActiveX 的框架来访问此对象。Crockford 和 Morningstar 能够使用此技术（在 IE 中）来获取数据，但是在 Netscape 4 中（这是他们想要支持的另一种浏览器）就无法使用这种解决方案。为此 Crockford 和 Morningstar 只得使用一套不同的系统以兼容不同的浏览器。第一条 JSON 消息如下所示： 消息中只有一小部分类似于今天我们所知的 JSON，本身其实是一个包含有一些 JavaScript 的 HTML 文档。类似于 JSON 的部分只是传递给名为 receive() 的函数的 JavaScript 对象字面量。Crockford 和 Morningstar 决定滥用 HTML 的帧（ ）以发送数据。他们可以让一个帧指向一个返回的上述 HTML 文档的 URL。当接收到 HTML 时，JavaScript 代码段就会运行，就可以把数据对象字面量如实地传递回应用程序。只要小心的回避浏览器保护策略（即子窗口不允许访问父窗口），这种技术就可以正常运行无误。可以看到 Crockford 和 Mornginstar 通过明确地设置文档域这种方法来达到其目的。（这种基于帧的技术，有时称为隐藏帧技术，通常在 90 年代后期，即在广泛使用 XMLHttpRequest 技术之前使用。 3 ）第一个 JSON 消息的惊人之处在于，它显然不是一种新的数据格式的首次使用。它就是 JavaScript！实际上，以此方式使用 JavaScript 的想法如此…

C++ 程序员 Protocol Buffers 基础指南
type: item
date: 2016-11-04T18:37:00+08:00
description: 这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍。通过创建一个简单的示例应用程序，它将向我们展示：在 .proto 文件中定义消息格式使用 protocol buffer 编译器使用 C++ protocol buffer API 读写消息这不是一个关于在 C++ 中使用 protocol buffers 的全面指南。要获取更详细的信息，请参考 Protocol Buffer Language Guide 和 Encoding Reference。为什么使用 Protocol Buffers我们接下来要使用的例子是一个非常简单的"地址簿"应用程序，它能从文件中读取联系人详细信息。地址簿中的每一个人都有一个名字、ID、邮件地址和联系电话。如何序列化和获取结构化的数据？这里有几种解决方案：以二进制形式发送/接收原生的内存数据结构。通常，这是一种脆弱的方法，因为接收/读取代码必须基于完全相同的内存布局、大小端等环境进行编译。同时，当文件增加时，原始格式数据会随着与该格式相关的软件而迅速扩散，这将导致很难扩展文件格式。你可以创造一种 ad-hoc 方法，将数据项编码为一个字符串——比如将 4 个整数编码为 12:3:-23:67。虽然它需要编写一次性的编码和解码代码且解码需要耗费一点运行时成本，但这是一种简单灵活的方法。这最适合编码非常简单的数据。序列化数据为 XML。这种方法是非常吸引人的，因为 XML 是一种适合人阅读的格式，并且有为许多语言开发的库。如果你想与其他程序和项目共享数据，这可能是一种不错的选择。然而，众所周知，XML 是空间密集型的，且在编码和解码时，它对程序会造成巨大的性能损失。同时，使用 XML DOM 树被认为比操作一个类的简单字段更加复杂。Protocol buffers 是针对这个问题的一种灵活、高效、自动化的解决方案。使用 Protocol buffers，你需要写一个 .proto 说明，用于描述你所希望存储的数据结构。利用 .proto 文件，protocol buffer 编译器可以创建一个类，用于实现对高效的二进制格式的 protocol buffer 数据的自动化编码和解码。产生的类提供了构造 protocol buffer 的字段的 getters 和 setters，并且作为一个单元来处理读写 protocol buffer 的细节。重要的是，protocol buffer 格式支持格式的扩展，代码仍然可以读取以旧格式编码的数据。在哪可以找到示例代码示例代码被包含于源代码包，位于“examples”文件夹。可在这里下载代码。定义你的协议格式为了创建自己的地址簿应用程序，你需要从 .proto 开始。.proto 文件中的定义很简单：为你所需要序列化的每个数据结构添加一个 消息 （ message ） ，然后为消息中的每一个字段指定一个名字和类型。这里是定义你消息的 .proto 文件 addressbook.proto。package tutorial; message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } message AddressBook { repeated Person person = 1; } 如你所见，其语法类似于 C++ 或 Java。我们开始看看文件的每一部分内容做了什么。.proto 文件以一个 package 声明开始，这可以避免不同项目的命名冲突。在 C++，你生成的类会被置于与 package 名字一样的命名空间。下一步，你需要定义 消息 （ message ） 。消息只是一个包含一系列类型字段的集合。大多标准的简单数据类型是可以作为字段类型的，包括 bool、int32、float、double 和 string。你也可以通过使用其他消息类型作为字段类型，将更多的数据结构添加到你的消息中——在以上的示例，Person 消息包含了 PhoneNumber 消息，同时 AddressBook 消息包含 Person 消息。你甚至可以定义嵌套在其他消息内的消息类型——如你所见，PhoneNumber 类型定义于 Person 内部。如果你…