mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
20171227 YAML- probably not so great after all.md翻译完成
This commit is contained in:
parent
b63af8822d
commit
bd11e3e579
@ -1,316 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (YAML: probably not so great after all)
|
||||
[#]: via: (https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html)
|
||||
[#]: author: (Martin Tournoij https://arp242.net/)
|
||||
|
||||
YAML: probably not so great after all
|
||||
======
|
||||
|
||||
|
||||
I previously wrote [why using JSON for human-editable configuration files is a bad idea][1]. Today we’re going to look at some general problems with the YAML format.
|
||||
|
||||
### Insecure by default
|
||||
|
||||
YAML is insecure by default. Loading a user-provided (untrusted) YAML string needs careful consideration.
|
||||
|
||||
```
|
||||
!!python/object/apply:os.system
|
||||
args: ['ls /']
|
||||
```
|
||||
|
||||
Running it with `print(yaml.load(open('a.yaml')))` should give you something like:
|
||||
|
||||
```
|
||||
bin etc lib lost+found opt root sbin tmp var sys
|
||||
boot dev efi home lib64 mnt proc run srv usr
|
||||
0
|
||||
```
|
||||
|
||||
Many other languages (including Ruby and PHP) are also unsafe by default. [Searching for `yaml.load` on GitHub][2] gives a whopping 2.8 million results. [`yaml.safe_load`][3] only gives 26,000 results.
|
||||
|
||||
Mind you, many of those `yaml.load()`s are fine – loading in a config file with `yaml.load()` is often okay since it’s usually (though not always!) from a ‘trusted source’, and many are from test files with static YAML. But still, one can’t help but wonder how many exploits are hidden in those 2.8 million results.
|
||||
|
||||
This is not a theoretical problem. In 2013 [every Ruby on Rails application ever written was found to be vulnerable][4] to remote code execution due to exactly this problem.
|
||||
|
||||
One might argue this is not really the fault of the YAML format as such, but rather the fault of the libraries implementing it wrong, but it seems to be the case that the majority of libraries are unsafe by default (especially the dynamic languages), so de-facto it is a problem with YAML.
|
||||
|
||||
One might also argue that fixing it is as easy as replacing `load()` with `safe_load()`, but many people are unaware of the problem, and even if you’re aware of it, it’s one of those things that can be easy to forget. It’s pretty bad API design.
|
||||
|
||||
### Can be hard to edit, especially for large files
|
||||
|
||||
YAML files can be hard to edit, and this difficulty grows fast as the file gets larger.
|
||||
|
||||
A good example of this are Ruby on Rails’ translation files; for example:
|
||||
|
||||
```
|
||||
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"
|
||||
```
|
||||
|
||||
This still looks okay, right? But what if this file has 100 lines? Or 1,000 lines? It is difficult to see “where” in the file you are because it may be off the screen. You’ll need to scroll up, but then you need to keep track of the indentation, which can be pretty hard even with indentation guides, especially since 2-space indentation is the norm and [tab indentation is forbidden][5].
|
||||
|
||||
And accidentally getting the indentation wrong often isn’t an error; it will often just deserialize to something you didn’t intend. Happy debugging!
|
||||
|
||||
I’ve been happily programming Python for over a decade, so I’m used to significant whitespace, but sometimes I’m still struggling with YAML. In Python the drawbacks and loss of clarity are contained by not having functions that are several pages long, but data or configuration files have no such natural limits to their length.
|
||||
|
||||
For small files this is not a problem; but it really doesn’t scale well to larger files, especially not if you want to edit them later on.
|
||||
|
||||
### It’s pretty complex
|
||||
|
||||
YAML may seem ‘simple’ and ‘obvious’ when glancing at a basic example, but turns out it’s not. The [YAML spec][6] is 23,449 words; for comparison, [TOML][7] is 3,339 words, [JSON][8] is 1,969 words, and [XML][9] is 20,603 words.
|
||||
|
||||
Who among us have read all that? Who among us have read and understood all of that? Who among of have read, understood, and **remembered** all of that?
|
||||
|
||||
For example did you know there are [nine ways to write a multi-line string in YAML][10] with subtly different behaviour?
|
||||
|
||||
Yeah :-/
|
||||
|
||||
That post gets even more interesting if you look at [its revision history][11], as the author of the post discovers more and more ways to do this and more of the subtleties involved.
|
||||
|
||||
It’s telling that the YAML spec starts with a preview, which states (emphases mine):
|
||||
|
||||
> This section provides a quick glimpse into the expressive power of YAML. **It is not expected that the first-time reader grok all of the examples**. Rather, these selections are used as motivation for the remainder of the specification.
|
||||
|
||||
#### Surprising behaviour
|
||||
|
||||
What does this parse to (examples courtesy of [Colm O’Connor][12]):
|
||||
|
||||
```
|
||||
- Don Corleone: Do you have faith in my judgment?
|
||||
- Clemenza: Yes
|
||||
- Don Corleone: Do I have your loyalty?
|
||||
```
|
||||
|
||||
Yup!
|
||||
|
||||
```
|
||||
[
|
||||
{'Don Corleone': 'Do you have faith in my judgment?'},
|
||||
{'Clemenza': True},
|
||||
{'Don Corleone': 'Do I have your loyalty?'}
|
||||
]
|
||||
```
|
||||
|
||||
Or what about:
|
||||
|
||||
```
|
||||
python: 3.5.3
|
||||
postgres: 9.3
|
||||
```
|
||||
|
||||
`3.5.3` gets recognized as as string, but `9.3` gets recognized as a number instead of a string:
|
||||
|
||||
```
|
||||
{'python': '3.5.3', 'postgres': 9.3}
|
||||
```
|
||||
|
||||
Or what about:
|
||||
|
||||
```
|
||||
Effenaar: Eindhoven
|
||||
013: Tilburg
|
||||
```
|
||||
|
||||
013 is a popular music Venue in Tilburg, but YAML will send you the wrong way since it’s parsed as an octal number:
|
||||
|
||||
```
|
||||
{11: 'Tilburg', 'Effenaar': 'Eindhoven'}
|
||||
```
|
||||
|
||||
All of this – and more – is why many experienced YAMLers will often quote all strings, even when it’s not strictly required. Many people don’t use quotes, and it can be easy to forget especially if the rest of the file – possibly written by other people – doesn’t use quotes.
|
||||
|
||||
#### It’s not portable
|
||||
|
||||
Because it’s so complex, its claims of portability have been greatly exaggerated. For example consider this example taken from the YAML spec:
|
||||
|
||||
```
|
||||
? - Detroit Tigers
|
||||
- Chicago cubs
|
||||
:
|
||||
- 2001-07-23
|
||||
|
||||
? [ New York Yankees,
|
||||
Atlanta Braves ]
|
||||
: [ 2001-07-02, 2001-08-12,
|
||||
2001-08-14 ]
|
||||
```
|
||||
|
||||
Aside from the fact that most readers of this probably won’t even know what this does, try parsing it in Python with PyYAML:
|
||||
|
||||
```
|
||||
yaml.constructor.ConstructorError: while constructing a mapping
|
||||
in "a.yaml", line 1, column 1
|
||||
found unhashable key
|
||||
in "a.yaml", line 1, column 3
|
||||
```
|
||||
|
||||
In Ruby it works:
|
||||
|
||||
```
|
||||
{
|
||||
["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)>
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The reason for this is because you can’t use a list as a dict key in Python:
|
||||
|
||||
```
|
||||
>>> {['a']: 'zxc'}
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: unhashable type: 'list'
|
||||
```
|
||||
|
||||
And this restriction is not unique to Python; common languages such as PHP, JavaScript, and Go all share this restriction.
|
||||
|
||||
So use this in a YAML file, and you won’t be able to read it in most languages.
|
||||
|
||||
Here’s another example again taken from the examples section of the YAML spec:
|
||||
|
||||
```
|
||||
# Ranking of 1998 home runs
|
||||
---
|
||||
- Mark McGwire
|
||||
- Sammy Sosa
|
||||
- Ken Griffey
|
||||
|
||||
# Team ranking
|
||||
---
|
||||
- Chicago Cubs
|
||||
- St Louis Cardinals
|
||||
```
|
||||
|
||||
Python says:
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
While Ruby outputs:
|
||||
|
||||
```
|
||||
["Mark McGwire", "Sammy Sosa", "Ken Griffey"]
|
||||
```
|
||||
|
||||
The reason for this is that there are multiple YAML documents in a single file (`---` start the document). In Python there is the `load_all()` function to parse all documents. Ruby’s `load()` just loads the first document, and as near as I can tell, doesn’t have a way to load multiple documents.
|
||||
|
||||
There are [many more incompatibilities between implementations][13].
|
||||
|
||||
### Goals achieved?
|
||||
|
||||
The spec states:
|
||||
|
||||
> The design goals for YAML are, in decreasing priority:
|
||||
>
|
||||
> 1. YAML is easily readable by humans.
|
||||
> 2. YAML data is portable between programming languages.
|
||||
> 3. YAML matches the native data structures of agile languages.
|
||||
> 4. YAML has a consistent model to support generic tools.
|
||||
> 5. YAML supports one-pass processing.
|
||||
> 6. YAML is expressive and extensible.
|
||||
> 7. YAML is easy to implement and use.
|
||||
>
|
||||
|
||||
|
||||
So how well does it do?
|
||||
|
||||
> YAML is easily readable by humans.
|
||||
|
||||
True only if you stick to a small subset. The full set is complex – much more so than XML or JSON.
|
||||
|
||||
> YAML data is portable between programming languages.
|
||||
|
||||
Not really true, as it’s too easy to create constructs that are not supported by common languages.
|
||||
|
||||
> YAML matches the native data structures of agile languages.
|
||||
|
||||
See above. Plus, why only support agile (or dynamic) languages? What about other languages?
|
||||
|
||||
> YAML has a consistent model to support generic tools.
|
||||
|
||||
I am not even sure what this means and I can’t find any elaboration.
|
||||
|
||||
> YAML supports one-pass processing.
|
||||
|
||||
I’ll take their word for it.
|
||||
|
||||
> YAML is expressive and extensible.
|
||||
|
||||
Well, it is, but it’s too expressive (e.g. too complex).
|
||||
|
||||
> YAML is easy to implement and use.
|
||||
|
||||
```
|
||||
$ 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
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
|
||||
Don’t get me wrong, it’s not like YAML is absolutely terrible – it’s certainly not as [problematic as using JSON][1] – but it’s not exactly great either. There are some drawbacks and surprises that are not at all obvious at first, and there are a number of better alternatives such as [TOML][7] and other more specialized formats.
|
||||
|
||||
Personally, I’m not likely to use it again when I’ve got a choice.
|
||||
|
||||
If you must use YAML then I recommend you use [StrictYAML][14], which removes some (though not all) of the more hairy parts.
|
||||
|
||||
### Feedback
|
||||
|
||||
You can mail me at [martin@arp242.net][15] or [create a GitHub issue][16] for feedback, questions, etc.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html
|
||||
|
||||
作者:[Martin Tournoij][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://arp242.net/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://arp242.net/weblog/JSON_as_configuration_files-_please_dont.html
|
||||
[2]: https://github.com/search?q=yaml.load&type=Code&utf8=%E2%9C%93
|
||||
[3]: https://github.com/search?q=yaml.safe_load&type=Code&utf8=%E2%9C%93
|
||||
[4]: https://www.sitepoint.com/anatomy-of-an-exploit-an-in-depth-look-at-the-rails-yaml-vulnerability/
|
||||
[5]: http://www.yaml.org/faq.html
|
||||
[6]: http://yaml.org/spec/1.2/spec.pdf
|
||||
[7]: https://github.com/toml-lang/toml
|
||||
[8]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
|
||||
[9]: https://www.w3.org/TR/REC-xml/
|
||||
[10]: http://stackoverflow.com/a/21699210/660921
|
||||
[11]: http://stackoverflow.com/posts/21699210/revisions
|
||||
[12]: https://github.com/crdoconnor/strictyaml/blob/master/FAQ.rst#what-is-wrong-with-implicit-typing
|
||||
[13]: https://github.com/cblp/yaml-sucks
|
||||
[14]: https://github.com/crdoconnor/strictyaml
|
||||
[15]: mailto:martin@arp242.net
|
||||
[16]: https://github.com/Carpetsmoker/arp242.net/issues/new
|
@ -0,0 +1,292 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (YAML: probably not so great after all)
|
||||
[#]: via: (https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html)
|
||||
[#]: author: (Martin Tournoij https://arp242.net/)
|
||||
|
||||
YAML: 可能并不是那么完美
|
||||
======
|
||||
|
||||
我之前写过[为什么将 JSON 用于人类可编辑的配置文件是一个坏主意][1],今天我们将讨论 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)默认情况下(to 校正:这里应该说的是解析 yaml)也不安全。[在 GitHub 上搜索 `yaml.load`][2] 会得到惊人的 280 万个结果,而 [`yaml.safe_load`][3] 只能得到 26,000 个结果。
|
||||
|
||||
提个醒,很多这样的 `yaml.load()` 都工作的很好,在配置文件中加载 `yaml.load()` 通常没问题,因为它通常(虽然并不总是!)来自“可靠源”,而且很多都来自静态的 YAML 测试文件。但是,人们还是不禁怀疑在这 280 万个结果中隐藏了多少漏洞。
|
||||
|
||||
这不是一个理论问题。在 2013 年,[正是由于这个问题,所有的 Ruby on Rails 应用程序都被发现易受][4]远程代码执行攻击。
|
||||
|
||||
有人可能会反驳说这不是 YAML 格式的错误,而是那些库实现错误的的问题,但似乎大多数库默认不是安全的(特别是动态语言),所以事实上这是 YAML 的一个问题。
|
||||
|
||||
有些人可能会反驳认为修复它就像用 `safe_load()` 替换 `load()` 一样容易,但是很多人都没有意识到这个问题,即使你知道它,它也是很容易忘记的事情之一。这是非常糟糕的 API 设计。
|
||||
|
||||
### 可能很难编辑,特别是对于大文件
|
||||
|
||||
YAML 文件可能很难编辑,随着文件变大,这个难度会快速增大。
|
||||
|
||||
一个很好的例子是 Ruby on Rails 的翻译文件。(to 校正:这里 translation files 是什么?)例如:
|
||||
```
|
||||
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 个缩进是常态而且 [tab 缩进被禁止][5]。
|
||||
|
||||
不小心缩进出错通常不是一个错误,它通常只是反序列化为你不想要的东西。这样只能祝你调试快乐!
|
||||
|
||||
我已经愉快地编写 Python 长达十多年,所以我已经习惯了显著的空白,但有时候我仍在和 YAML 抗争。在 Python 中,缺点和清晰度的丧失是由于没有那种长达几页的函数,但数据或配置文件的长度没有这种自然限制。(to 校正:这里不太明白为什么没有长达几页函数会导致 python 清晰度的丧失,或许我的翻译有问题)
|
||||
|
||||
对于小文件,这不是问题,但它确实无法很好地扩展到较大的文件,特别是如果你以后想编辑它们的话。
|
||||
|
||||
### 这非常复杂
|
||||
|
||||
在浏览一个基本的例子时,YAML 看似“简单”和“显而易见”,但事实证明并非如此。[YAML 规范][6]有 23,449 个单词,为了比较,[TOML][7] 有 3,339 个单词,[Json][8] 有 1,969 个单词,[XML][9] 有 20,603 个单词。
|
||||
|
||||
我们中有谁读过全部吗?有谁读过并理解了全部?谁阅读过,理解进而**记住**所有这些?
|
||||
|
||||
例如,你知道有[ 9 种方法在 YAML 中编写多行字符串][10]吗?并且它们具有细微的不同行为。
|
||||
|
||||
是的 :-/
|
||||
|
||||
如果你看一下[它的修订历史][11],那篇文章就会变得更加有趣,因为文章的作者发现了越来越多的方法可以实现这一点,以及更多的细微之处。
|
||||
|
||||
它从预览开始告诉我们 YANL 规范,它表明(强调我的):
|
||||
|
||||
> 本节简要介绍了 YAML 的表达能力。**初次阅读的人不可能熟读所有的例子**。相反,这些选择用作规范其余部分的动机。
|
||||
|
||||
#### 惊讶的行为
|
||||
|
||||
以下会解析成什么([Colm O’Connor][12] 提供的例子):
|
||||
```
|
||||
- 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'}
|
||||
```
|
||||
|
||||
所有这一切,以及更多,就是为什么许多经验丰富的 YAMLers 经常会引用所有字符串的原因,即使它不是严格要求。许多人不使用引号,而且很容易忘记,特别是如果文件的其余部分(可能由其他人编写)不使用引号。
|
||||
|
||||
### 它不方便
|
||||
|
||||
因为它太复杂了,它声称的可移植性被夸大了。例如,考虑以下这个从 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 中使用列表作为一个字典(dict)键:
|
||||
```
|
||||
>>> {['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()` 只是加载第一个文档,据我所知,它没有办法加载多个文档。
|
||||
|
||||
[在实现之间存在很多不兼容][13]。
|
||||
|
||||
### 目标实现了吗?
|
||||
|
||||
规范说明:
|
||||
|
||||
> YAML 的设计目标是降低优先级:
|
||||
>
|
||||
> 1. YAML 很容易被人类阅读。
|
||||
> 2. YAML 数据在编程语言之间是可移植的。
|
||||
> 3. YAML 匹配敏捷语言的原生数据结构。
|
||||
> 4. YAML 有一个一致的模型来支持通用工具。
|
||||
> 5. YAML 支持一趟处理。(to 校正:这里 one-pass 是否有专业翻译?)
|
||||
> 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 那么多的问题][1] - 但它也不是非常好。有一些一开始并不明显的缺点和惊喜,还有许多更好的替代品,如 [TOML][7] 和其他更专业的格式。
|
||||
|
||||
就个人而言,当我有选择时,我不太可能再次使用它。
|
||||
|
||||
如果你必须使用 YAML,那么我建议你使用 [StrictYAML][14],它会删除一些(虽然不是全部)比较麻烦的部分。
|
||||
|
||||
### 反馈
|
||||
|
||||
你可以发送电子邮件至 [martin@arp242.net][15] 或[创建 GitHub issue][16] 以获取反馈,问题等。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html
|
||||
|
||||
作者:[Martin Tournoij][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://arp242.net/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://arp242.net/weblog/JSON_as_configuration_files-_please_dont.html
|
||||
[2]: https://github.com/search?q=yaml.load&type=Code&utf8=%E2%9C%93
|
||||
[3]: https://github.com/search?q=yaml.safe_load&type=Code&utf8=%E2%9C%93
|
||||
[4]: https://www.sitepoint.com/anatomy-of-an-exploit-an-in-depth-look-at-the-rails-yaml-vulnerability/
|
||||
[5]: http://www.yaml.org/faq.html
|
||||
[6]: http://yaml.org/spec/1.2/spec.pdf
|
||||
[7]: https://github.com/toml-lang/toml
|
||||
[8]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
|
||||
[9]: https://www.w3.org/TR/REC-xml/
|
||||
[10]: http://stackoverflow.com/a/21699210/660921
|
||||
[11]: http://stackoverflow.com/posts/21699210/revisions
|
||||
[12]: https://github.com/crdoconnor/strictyaml/blob/master/FAQ.rst#what-is-wrong-with-implicit-typing
|
||||
[13]: https://github.com/cblp/yaml-sucks
|
||||
[14]: https://github.com/crdoconnor/strictyaml
|
||||
[15]: mailto:martin@arp242.net
|
||||
[16]: https://github.com/Carpetsmoker/arp242.net/issues/new
|
Loading…
Reference in New Issue
Block a user