标签 YAML 下的文章

YAML 看起来很简单,为什么它这么难写呢?了解成功使用 YAML 的两个秘诀。

 title=

如果你曾经尝试过写 YAML,你可能一开始会对它看起来很容易感到高兴。乍一看,经常用于配置文件、Ansible 剧本和普通文件数据库的 YAML 看起来就像购物清单一样直观。然而,YAML 的结构中有很多细微的差别,它隐藏着一个危险的秘密:YAML 实际上是一种高度精确、结构化和令人惊讶的严格语言。好消息是,你只需要了解两件事就可以知道 YAML 的工作原理。

关于 YAML 的真相是,YAML 中只有两种数据结构: 序列 sequence 映射 mapping 。这是两个花哨的名字,你会发现它代表了你非常熟悉的概念。这篇文章解释了这两种结构,更重要的是,介绍了它们是如何协同工作,使 YAML 成为表示你所关心的数据的强大方式。

YAML 序列

YAML 序列是一个列表。在其最简单的形式中,每行有一个项目,每行以破折号和空格开始。

下面是一个例子:

---
- Linux
- BSD
- Illumos

不同的语言有不同的方式来表示这种数据。例如,在 Python 中,同一个列表可以写成 ['Linux', 'BSD', 'Illumos']。当你在现实生活中写一个列表时,例如在你去买菜之前,你写的可能近似于 YAML 序列。

YAML 映射

YAML 映射是一个关键术语与该术语的定义相结合。在其他语言中,映射被称为“键值对”或“词典”。

这里有一个例子:

---
Kernel: Linux
CPU: AMD
RAM: '16 GB'

不同的语言有不同的方式来表示这种数据。在 Python 中,例如,同样的数据可以写成 {"Kernel": "Linux", "CPU": "AMD", "RAM": "16 GB"}。在现实生活中,你可能会使用这种结构来计划,例如,与朋友的游戏之夜。一个朋友报名带零食,另一个报名带一副牌,另一个报名带一个棋盘游戏,等等。

组合序列和映射

你现在知道 YAML 的语法了。序列和映射是 YAML 中仅有的两种构件,你想在 YAML 中表示的任何东西都可以放在序列或映射中。

或者同时使用这二者!

是的,序列和映射可以被组合和嵌套,这就是 YAML 看起来很直观,但同时又感觉很复杂的原因之一。不过,只有四种可能的组合,一旦你学会如何看它们,YAML 就会觉得像它看起来一样简单。

序列的映射

当你想让一个键项有许多值时,你可以使用一个序列的映射。也就是说,你从一个映射(键)开始,但是给值一个列表:

---
Linux:
  - Fedora
  - Slackware
BSD:
  - FreeBSD
  - NetBSD

在这个示例代码中,Linux 是第一个键,它的值是一个序列,其中包含 FedoraSlackware。第二个键是 BSD,它的值是一个序列,包含 FreeBSDNetBSD

映射的映射

当你想让一个键项的值中既有键又有值时,你可以使用映射的映射。也就是说,你从一个映射(键)开始,但是给值另一个映射。

这可能有点欺骗性,但它揭示了 YAML 中使用特定术语的原因:因为你只不过是创建了一个映射的列表,并不意味着你创建了一个序列。这里是一个映射的映射:

---
Desktop:
  CPU: RISC-V
  RAM: '32 GB'
Laptop:
  CPU: AMD
  RAM: '16 GB'

对大多数人来说,这看起来像一个列表。而且从技术上讲,它是一个列表。但重要的是要认识到,它不是 YAML 序列。它是一个映射,其中包含映射。作为半个 YAML 专家,你可以从明显缺少破折号的地方看出区别。

在 Ansible 剧本的所有结构中,我发现这个结构最容易欺骗人。作为人类,我们喜欢列表,当我们看到一个数据结构 在字面上 是列表时,大多数人会把它当成 YAML 序列。但是在 YAML 中,虽然序列是列表,但是列表并不总是序列。

序列的序列

就像你可以嵌套映射一样,你可以将一个序列嵌套到一个序列中:

---
- [Linux, FreeBSD, Illumos]
- [YAML, XML, JSON]

这可能是我在 YAML 的实际使用中遇到的最不常见的数据结构,但有时你需要一个列表的列表。

映射的序列

你也可以创建一个包含映射的序列。对于人类排序数据的方式来说,这并不太常见,但对于计算机来说,这可能是一个重要的结构。

这里有一个例子:

---
-
  CPU: AMD
  RAM: '16 GB'
-
  CPU: Intel
  RAM: '16 GB'

对于 YAML,这可能是最不直观的语法。我发现它在 Python 中呈现时更清晰:

[{"CPU": "AMD", "RAM": "16 GB"}, {"CPU": "Intel", "RAM": "16 GB"}]

方括号代表一个列表结构,这个列表包含两个字典。每个字典都包含键值对。

构建更好的 YAML

现在你知道了 YAML 的两个组成部分,以及它们如何被组合起来以表示复杂的数据结构。问题是:你要用 YAML 构建什么?

和很多人一样,我也使用 YAML 来编写 Ansible 剧本。我还用它作为一种简单的配置格式、作为 D&D 的角色表、表示项目组织所需的目录结构,等等。只要你能适应序列和映射的概念,你会发现 YAML 是一种很容易编写、阅读和(如果有合适的库)解析的格式。

如果你发现自己经常使用 YAML,请下载我们的 YAML 速查表,以帮助你直观地了解基本数据结构及其组合,并帮助你记住一些额外的语法约定。通过一点点的练习,你会发现 YAML 真的和它看起来一样简单!


via: https://opensource.com/article/21/9/yaml-cheat-sheet

作者:Seth Kenlon 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

什么是 YAML,为什么我们现在应该开始使用它?

 title=

YAML YAML 不是标记语言 YAML Ain't Markup Language )是一种适宜阅读理解的数据序列化语言。它的语法简单而易于阅读。它不包含引号、打开和关闭的标签或大括号。它不包含任何可能使人类难以解析嵌套规则的东西。你可以看一下你的 YAML 文档就知道它在什么。

YAML 特性

YAML 有一些超级特性,使其优于其他序列化格式:

  • 易于略读。
  • 易于使用。
  • 可在编程语言之间移植。
  • 敏捷语言的原生数据结构。
  • 支持通用工具的一致模型。
  • 支持一次性处理。
  • 表现力和可扩展性。

我将通过一些例子进一步向你展示 YAML 的强大。

你能弄清楚下面发生了什么吗?

-------
# My grocery list
groceries:
    - Milk
    - Eggs
    - Bread
    - Butter
...

上面的例子包含了一个简单的杂货购物清单,它是一个完全格式化的 YAML 文档。在 YAML 中,字符串不加引号,而列表需要简单的连字符和空格。一个 YAML 文档以 --- 开始,以 ... 结束,但它们是可选的。YAML中的注释以 # 开始。

缩进是 YAML 的关键。缩进必须包含空格,而不是制表符。虽然所需的空格数量是灵活的,但保持一致是个好主意。

基本元素

集合

YAML 有两种类型的集合。列表(用于序列)和字典(用于映射)。列表是键值对,每个值都在一个新的行中,以连字符和空格开始。字典也是键值对,每个值都是一个映射,包含一个键、一个冒号和空格以及一个值。

例如:

# My List
groceries:
    - Milk
    - Eggs
    - Bread
    - Butter

# My dictionary
contact:
    name: Ayush Sharma
    email: [email protected]

列表和字典经常被结合起来,以提供更复杂的数据结构。列表可以包含字典,而字典可以包含列表。

字符串

YAML 中的字符串不需要加引号。多行字符串可以用 |> 来定义。前者保留了换行符,而后者则没有。

例如:

my_string: |
    This is my string.
    It can contain many lines.
    Newlines are preserved.
my_string_2: >
    This is my string.
    This can also contain many lines.
    Newlines aren't preserved and all lines are folded.

锚点

YAML 可以通过节点锚点来获得可重复的数据块。& 字符定义了一个数据块,以后可以用 * 来引用。例如:

billing_address: &add1
    house: B1
    street: My Street

shipping_address: *add1

至止你对 YAML 的了解就足以让你开始工作了。你可以使用在线 YAML 解析器来测试。如果你每天都与 YAML 打交道,那么 这个方便的备忘单 会对你有所帮助。

这篇文章最初发表在作者的个人博客上,并经授权改编。


via: https://opensource.com/article/21/9/intro-yaml

作者:Ayush Sharma 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

一段超级严肃的关于样本序列化的集合、子集和超集的文字

我是一名开发者,我读代码,我写代码,我写会写代码的代码,我写会写出供其它代码读的代码的代码。这些都非常火星语,但是有其美妙之处。然而,最后一点,写会写出供其它代码读的代码的代码,可以很快变得比这段文字更费解。有很多方法可以做到这一点。一种不那么复杂而且开发者社区最爱的方式是数据序列化。对于那些不了解我刚刚抛给你的时髦词的人,数据序列化是从一个系统获取一些信息,将其转换为其它系统可以读取的格式,然后将其传递给其它系统的过程。

虽然数据序列化格式多到可以埋葬哈利法塔,但它们大多分为两类:

  • 易于人类读写,
  • 易于机器读写。

很难两全其美,因为人类喜欢让我们更具表现力的松散类型和灵活格式标准,而机器倾向于被确切告知一切事情而没有二义性和细节缺失,并且认为“严格规范”才是它们最爱的口味。

由于我是一名 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>
<title>XML Developer's Guide</title>
<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="&y;>" />
<![CDATA[[a>b <a>b <a]]>
<?x <a> <!-- <b> ?> c --> d
</r>

这上面是 100% 有效的 XML。几乎不可能阅读、理解或推理。编写可以使用和理解这个的代码将花费至少 36 根头发和 248 磅咖啡渣。我们没有那么多时间或咖啡,而且我们大多数老程序员们现在都是秃头。所以,让它活在我们的记忆里,就像 css hacksIE 6 浏览器真空管一样好了。

JSON:并列聚会

好吧,我们都同意,XML = 差劲。那么,好的替代品是什么? JavaScript 对象表示法 JavaScript Object Notation ,简称 JSON。JSON(读起来像 Jason 这个名字) 是 Brendan Eich 发明的,并且得到了伟大而强力的 JavaScript 意见领袖 Douglas Crockford 的推广。它现在几乎用在任何地方。这种格式很容易由人和机器编写,按规范中的严格规则解析也相当容易,并且灵活 —— 允许深层嵌套数据,支持所有的原始数据类型,及将集合解释为数组或对象。JSON 成为了将数据从一个系统传输到另一个系统的事实标准。几乎所有语言都有内置读写它的功能。

JSON语法很简单。方括号表示数组,花括号表示记录,由冒号分隔的两个值分别表示属性或“键”(在左边)、值(在右边)。所有键必须用双引号括起来:

  {
    "books": [
      {
        "id": "bk102",
        "author": "Crockford, Douglas",
        "title": "JavaScript: The Good Parts",
        "genre": "Computer",
        "price": 29.99,
        "publish_date": "2008-05-01",
        "description": "Unearthing the Excellence in JavaScript"
      }
    ]
  }

这对你来说应该是完全有意义的。它简洁明了,并且从 XML 中删除了大量额外废话,并传达相同数量的信息。JSON 现在是王道,本文剩下的部分会介绍其它语言格式,这些格式只不过是 JSON 的简化版,尝试让其更简洁或对人类更易读,可结构还是非常相似的。

TOML: 缩短到彻底的利他主义

TOML( Tom 的显而易见的最小化语言 Tom’s Obvious, Minimal Language )允许以相当快捷、简洁的方式定义深层嵌套的数据结构。名字中的 Tom 是指发明者 Tom Preston Werner,他是一位活跃于我们行业的创造者和软件开发人员。与 JSON 相比,语法有点尴尬,更类似 ini 文件。这不是一个糟糕的语法,但是需要一些时间适应。

[[books]]
id = 'bk101'
author = 'Crockford, Douglas'
title = 'JavaScript: The Good Parts'
genre = 'Computer'
price = 29.99
publish_date = 2008-05-01T00:00:00+00:00
description = 'Unearthing the Excellence in JavaScript'

TOML 中集成了一些很棒的功能,例如多行字符串、保留字符的自动转义、日期、时间、整数、浮点数、科学记数法和“表扩展”等数据类型。最后一点是特别的,是 TOML 如此简洁的原因:

[a.b.c]
d = 'Hello'
e = 'World'

以上扩展到以下内容:

{
  "a": { 
    "b": {
      "c": { 
        "d": "Hello"
        "e": "World"
      }
    }
  }
}

使用 TOML,你可以肯定在时间和文件长度上会节省不少。很少有系统使用它或非常类似的东西作为配置,这是它最大的缺点。根本没有很多语言或库可以用来解释 TOML。

CSON: 特定系统所包含的简单样本

首先,有两个 CSON 规范。 一个代表 CoffeeScript Object Notation,另一个代表 Cursive Script Object Notation。后者不经常使用,所以我们不会关注它。我们只关注 CoffeeScript。

CSON 需要一点介绍。首先,我们来谈谈 CoffeeScript。CoffeeScript 是一种通过运行编译器生成 JavaScript 的语言。它允许你以更加简洁的语法编写 JavaScript 并转译成实际的 JavaScript,然后你可以在你的 web 应用程序中使用它。CoffeeScript 通过删除 JavaScript 中必需的许多额外语法,使编写 JavaScript 变得更容易。CoffeeScript 摆脱的一个大问题是花括号 —— 不需要它们。同样,CSON 是没有大括号的 JSON。它依赖于缩进来确定数据的层次结构。CSON 非常易于读写,并且通常比 JSON 需要更少的代码行,因为没有括号。

CSON 还提供一些 JSON 不提供的额外细节。多行字符串非常容易编写,你可以通过使用 # 符号开始一行来输入注释),并且不需要用逗号分隔键值对。

books: [
  id: 'bk102'
  author: 'Crockford, Douglas'
  title: 'JavaScript: The Good Parts'
  genre: 'Computer'
  price: 29.99
  publish_date: '2008-05-01'
  description: 'Unearthing the Excellence in JavaScript'
]

这是 CSON 的大问题。它是 CoffeScript 对象表示法 CoffeeScript Object Notation 。也就是说你要用 CoffeeScript 解析/标记化/lex/转译或其它方式来使用 CSON。CoffeeScript 是读取数据的系统。如果数据序列化的目的是允许数据从一个系统传递到另一个系统,这里我们有一个只能由单个系统读取的数据序列化格式,这使得它与防火火柴、防水海绵或者叉匙恼人的脆弱叉子部分一样有用。

如果这种格式被其它系统也采用,那它在开发者世界中可能非常有用。但到目前为止这基本上没有发生,所以在 PHP 或 JAVA 等替代语言中使用它是不行的。

YAML:年轻人的呼喊

开发人员感到高兴,因为 YAML 来自一个 Python 的贡献者。YAML 具有与 CSON 相同的功能集和类似的语法,有一系列新功能,以及几乎所有 web 编程语言都可用的解析器。它还有一些额外的功能,如循环引用、软包装、多行键、类型转换标签、二进制数据、对象合并和集合映射。它具有非常好的可读性和可写性,并且是 JSON 的超集,因此你可以在 YAML 中使用完全合格的 JSON 语法并且一切正常工作。你几乎不需要引号,它可以解释大多数基本数据类型(字符串、整数、浮点数、布尔值等)。

books:
  - id: bk102
  author: Crockford, Douglas
  title: 'JavaScript: The Good Parts'
  genre: Computer
  price: 29.99
  publish_date: !!str 2008-05-01
  description: Unearthing the Excellence in JavaScript

业界的年轻人正在迅速采用 YAML 作为他们首选的数据序列化和系统配置格式。他们这样做很机智。YAML 具有像 CSON 一样简洁的所有好处,以及与 JSON 一样的数据类型解释的所有功能。YAML 像加拿大人容易相处一样容易阅读。

YAML 有两个问题,对我而言,第一个是大问题。在撰写本文时,YAML 解析器尚未内置于多种语言,因此你需要使用第三方库或扩展来为你选择的语言解析 .yaml 文件。这不是什么大问题,可似乎大多数为 YAML 创建解析器的开发人员都选择随机将“附加功能”放入解析器中。有些允许标记化,有些允许链引用,有些甚至允许内联计算。这一切都很好(某种意义上),只是这些功能都不是规范的一部分,因此很难在其他语言的其他解析器中找到。这导致系统限定,你最终遇到了与 CSON 相同的问题。如果你使用仅在一个解析器中找到的功能,则其他解析器将无法解释输入。大多数这些功能都是无意义的,不属于数据集,而是属于你的应用程序逻辑,因此最好简单地忽略它们和编写符合规范的 YAML。

第二个问题是很少有解析器完全实现规范。所有的基本要素都有,但是很难找到一些更复杂和更新的东西,比如软包装、文档标记和首选语言的循环引用。我还没有看到对这些东西的刚需,所以希望它们不让你很失望。考虑到上述情况,我倾向于保持 1.1 规范 中呈现的更成熟的功能集,而避免在 1.2 规范 中找到的新东西。然而,编程是一个不断发展的怪兽,所以当你读完这篇文章时,你或许就可以使用 1.2 规范了。

最终哲学

这是最后一段话。每个序列化语言都应该以个案标准的方式评价。当涉及机器的可读性时,有些 无出其右 the bee’s knees 。对于人类可读性,有些 名至实归 the cat’s meow ,有些只是 金玉其外 gilded turds 。以下是最终细分:如果你要编写供其他代码阅读的代码,请使用 YAML。如果你正在编写能写出供其他代码读取的代码的代码,请使用 JSON。最后,如果你正在编写将代码转译为供其他代码读取的代码的代码,请重新考虑你的人生选择。


via: https://www.zionandzion.com/json-vs-xml-vs-toml-vs-cson-vs-yaml/

作者:Tim Anderson 选题:lujun9972 译者:GraveAccent 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

我之前写过为什么将 JSON 用于人类可编辑的配置文件是一个坏主意,今天我们将讨论 YAML 格式的一些常见问题。

默认情况下不安全

YAML 默认是不安全的。加载用户提供的(不可信的)YAML 字符串需要仔细考虑。

!!python/object/apply:os.system
args: ['ls /']

print(yaml.load(open('a.yaml'))) 运行它,应该给你这样的东西:

bin   etc   lib    lost+found  opt   root  sbin  tmp  var sys
boot  dev   efi    home        lib64 mnt   proc  run  srv usr
0

许多其他语言(包括 Ruby 和 PHP 1 )默认情况下也不安全(LCTT 译注:这里应该说的是解析 yaml)。在 GitHub 上搜索 yaml.load 会得到惊人的 280 万个结果,而 yaml.safe\_load 只能得到 26000 个结果。

提个醒,很多这样的 yaml.load() 都工作的很好,在配置文件中加载 yaml.load() 通常没问题,因为它通常(虽然并不总是!)来自“可靠源”,而且很多都来自静态的 YAML 测试文件。但是,人们还是不禁怀疑在这 280 万个结果中隐藏了多少漏洞。

这不是一个理论问题。在 2013 年,正是由于这个问题,所有的 Ruby on Rails 应用程序都被发现易受远程代码执行攻击。

有人可能会反驳说这不是 YAML 格式的错误,而是那些库实现错误的的问题,但似乎大多数库默认不是安全的(特别是动态语言),所以事实上这是 YAML 的一个问题。

有些人可能会反驳认为修复它就像用 safe_load() 替换 load() 一样容易,但是很多人都没有意识到这个问题,即使你知道它,它也是很容易忘记的事情之一。这是非常糟糕的 API 设计。

可能很难编辑,特别是对于大文件

YAML 文件可能很难编辑,随着文件变大,这个难度会快速增大。

一个很好的例子是 Ruby on Rails 的本地化翻译文件。例如:

en:
   formtastic:
     labels:
       title: "Title"  # Default global value
       article:
         body: "Article content"
       post:
         new:
           title: "Choose a title..."
           body: "Write something..."
         edit:
           title: "Edit title"
           body: "Edit body"

看起来不错,对吧?但是如果这个文件有 100 行怎么办?或者 1,000 行?在文件中很难看到 “where”,因为它可能在屏幕外。你需要向上滚动,但是你需要跟踪缩进,即使遵循缩进指南也很难,特别是因为 2 个空格缩进是常态而且 制表符缩进被禁止 2

不小心缩进出错通常不算错误,它通常只是反序列化为你不想要的东西。这样只能祝你调试快乐!

我已经愉快地编写 Python 长达十多年,所以我已经习惯了显眼的空白,但有时候我仍在和 YAML 抗争。在 Python 中,虽然没有那种长达几页的函数,但数据或配置文件的长度没有这种自然限制,这就带来了缺点和损失了清晰度。

对于小文件,这不是问题,但它确实无法很好地扩展到较大的文件,特别是如果你以后想编辑它们的话。

这非常复杂

在浏览一个基本的例子时,YAML 看似“简单”和“显而易见”,但事实证明并非如此。YAML 规范有 23449 个单词,为了比较,TOML 有 3339 个单词,Json 有 1969 个单词,XML 有 20603 个单词。

我们中有谁读过全部规范吗?有谁读过并理解了全部?谁阅读过,理解进而记住所有这些?

例如,你知道在 YAML 中编写多行字符串有 9 种方法吗?并且它们具有细微的不同行为。

是的 :-/

如果你看一下那篇文章的修订历史,它就会变得更加有趣,因为文章的作者发现了越来越多的方法可以实现这一点,以及更多的细微之处。

它从预览开始告诉我们 YAML 规范,它表明(强调我的):

本节简要介绍了 YAML 的表达能力。预计初次阅读的人不可能理解所有的例子。相反,这些选择用作该规范其余部分的动机。

令人惊讶的行为

以下会解析成什么(Colm O’Connor 提供的例子):

- Don Corleone: Do you have faith in my judgment?
- Clemenza: Yes
- Don Corleone: Do I have your loyalty?

结果为:

[
    {'Don Corleone': 'Do you have faith in my judgment?'},
    {'Clemenza': True},
    {'Don Corleone': 'Do I have your loyalty?'}
]

那么这个呢:

python: 3.5.3
postgres: 9.3

3.5.3 被识别为字符串,但 9.3 被识别为数字而不是字符串:

{'python': '3.5.3', 'postgres': 9.3}

这个呢:

Effenaar: Eindhoven
013: Tilburg

013 蒂尔堡 Tilburg 的一个流行音乐场地,但 YAML 会告诉你错误答案,因为它被解析为八进制数字:

{11: 'Tilburg', 'Effenaar': 'Eindhoven'}

所有这一切,以及更多,就是为什么许多经验丰富的 YAMLer 经常会将所有字符串用引号引起来的原因,即使它不是严格要求。许多人不使用引号,而且很容易忘记,特别是如果文件的其余部分(可能由其他人编写)不使用引号。

它不方便

因为它太复杂了,它所声称的可移植性被夸大了。例如,考虑以下这个从 YAML 规范中获取的示例:

? - Detroit Tigers
  - Chicago cubs
:
  - 2001-07-23

? [ New York Yankees,
    Atlanta Braves ]
: [ 2001-07-02, 2001-08-12,
    2001-08-14 ]

抛开大多数读者可能甚至不知道这是在做什么之外,请尝试使用 PyYAML 在 Python 中解析它:

yaml.constructor.ConstructorError: while constructing a mapping
  in "a.yaml", line 1, column 1
found unhashable key
  in "a.yaml", line 1, column 3

在 Ruby 中,它可以工作:

{
    ["Detroit Tigers", "Chicago cubs"] => [
        #<Date: 2001-07-23 ((2452114j,0s,0n),+0s,2299161j)>
    ],
    ["New York Yankees", "Atlanta Braves"] => [
        #<Date: 2001-07-02 ((2452093j,0s,0n),+0s,2299161j)>,
        #<Date: 2001-08-12 ((2452134j,0s,0n),+0s,2299161j)>,
        #<Date: 2001-08-14 ((2452136j,0s,0n),+0s,2299161j)>
    ]
}

这个原因是你不能在 Python 中使用列表作为一个字典的键:

>>> {['a']: 'zxc'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: unhashable type: 'list'

而这种限制并不是 Python 特有的,PHP、JavaScript 和 Go 等常用语言都有此限制。

因此,在 YAML 文件中使用这种语法,你将无法在大多数语言中解析它。

这是另一个从 YAML 规范的示例部分中获取的:

# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey

# Team ranking
---
- Chicago Cubs
- St Louis Cardinals

Python 会输出:

yaml.composer.ComposerError: expected a single document in the stream
  in "a.yaml", line 3, column 1
but found another document
  in "a.yaml", line 8, column 1

然而 Ruby 输出:

["Mark McGwire", "Sammy Sosa", "Ken Griffey"]

原因是单个文件中有多个 YAML 文档(--- 意味开始一个新文档)。在 Python 中,有一个 load_all 函数来解析所有文档,而 Ruby 的 load() 只是加载第一个文档,据我所知,它没有办法加载多个文档。

在实现之间存在很多不兼容

目标实现了吗?

规范说明:

YAML 的设计目标安装优先级降序排列如下:

  1. YAML 很容易被人类阅读。
  2. YAML 数据在编程语言之间是可移植的。
  3. YAML 匹配敏捷语言的原生数据结构。
  4. YAML 有一个一致的模型来支持通用工具。
  5. YAML 支持一次性处理。
  6. YAML 具有表现力和可扩展性。
  7. YAML 易于实现和使用。

那么它做的如何呢?

YAML 很容易被人类阅读。

只有坚持一小部分子集时才有效。完整的规则集很复杂 —— 远远超过 XML 或 JSON。

YAML 数据在编程语言之间是可移植的。

事实并非如此,因为创建常见语言不支持的结构太容易了。

YAML 匹配敏捷语言的原生数据结构。

参见上面。另外,为什么只支持敏捷(或动态)语言?其他语言呢?

YAML 有一个一致的模型来支持通用工具。

我甚至不确定这意味着什么,我找不到任何详细说明。

YAML 支持一次性处理。

这点我接受。

YAML 具有表现力和可扩展性。

嗯,是的,但它太富有表现力(例如太复杂)。

YAML 易于实现和使用。
$ cat `ls -1 ~/gocode/src/github.com/go-yaml/yaml/*.go | grep -v _test` | wc -l
9247

$ cat /usr/lib/python3.5/site-packages/yaml/*.py | wc -l
5713

结论

不要误解我的意思,并不是说 YAML 很糟糕 —— 它肯定不像使用 JSON 那么多的问题 —— 但它也不是非常好。有一些一开始并不明显的缺点和惊喜,还有许多更好的替代品,如 TOML 和其他更专业的格式。

就个人而言,当我有选择时,我不太可能再次使用它。

如果你必须使用 YAML,那么我建议你使用 StrictYAML,它会删除一些(虽然不是全部)比较麻烦的部分。

反馈

你可以发送电子邮件至 [email protected]创建 GitHub issue 以获取反馈、问题等。

脚注

  1. 在 PHP 中你需要修改一个 INI 设置来获得安全的行为,不能只是调用像 yaml_safe() 这样的东西。PHP 想尽办法让愚蠢的东西越发愚蠢。干得漂亮!
  2. 不要在这里做空格与制表符之争,如果这里可以用制表符的话,我可以(临时)增加制表符宽度来使它更易读——这是制表符的一种用途。

via: https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html

作者:Martin Tournoij 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出