python - 从文件加载特定的 PyYAML 文档

标签 python python-2.7 yaml pyyaml

我有一个 .yml 文件,我正在尝试从中加载某些文档。我知道:

print yaml.load(open('doc_to_open.yml', 'r+'))

将打开 .yml 文件中的第一个(或唯一)文档,并且:

for x in yaml.load_all(open('doc_to_open.yml', 'r+')):
    print x

这将打印文件中的所有 YAML 文档。但是假设我只想打开文件中的前三个文档,或者想打开文件中的第 8 个文档。我该怎么做?

最佳答案

如果您根本不想解析前七个 YAML 文件,例如出于效率原因,您必须自己搜索第 8 个文档。

可以挂接到解析器的第一阶段并计算流中 DocumentStartTokens() 的数量,并且仅在第 8 个之后开始传递 token 并停止这样做9 号,但这样做绝非易事。至少,这仍然会标记化所有前面的文档。

完全低效的方法(IMO)需要表现相同的有效替代方法,即在完成标记化/解析/后使用 .load_all() 并选择适当的文档/撰写/解决所有文档 ¹:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
for idx, data in enumerate(yaml.load_all(open('input.yaml'):
    if idx == 7:
        yaml.dump(data, sys.stdout)

如果您在文档 input.yaml 上运行上述内容:

---
document: 0
---
document: 1
---
document: 2
---
document: 3
---
document: 4
---
document: 5
---
document: 6
---
document: 7   # < the 8th document
---
document: 8
---
document: 9
...

你得到输出:

document: 7   # < the 8th document

不幸的是,你不能天真地只计算文档 markers 的数量(---),因为文档不必以 1 开头:

document: 0
---
document: 1
.
.

如果文件以 directive 开头,则第一行也不必有标记。 ²:

%YAML 1.2
---
document: 0
---
document: 1
.
.

或以仅包含注释的“文档”开头:

# the 8th document is the interesting one
---
document: 0
---
document: 1
.
.

考虑到您可以使用的所有内容:

def get_nth_yaml_doc(stream, doc_nr):
    doc_idx = 0
    data = []
    for line in stream:
        if line == u'---\n' or line.startswith('--- '):
            doc_idx += 1
            continue
        if line == '...\n':
            break
        if doc_nr < doc_idx:
            break
        if line.startswith(u'%'):
            continue
        if doc_idx == 0:  # no initial '---' YAML files don't start with
            if line.lstrip().startswith('#'):
                continue
            doc_idx = 1
        if doc_idx == doc_nr:
            data.append(line)
    return yaml.load(''.join(data))

with open("input.yaml") as fp:
    data = get_nth_yaml_doc(fp, 8)
yaml.dump(data, sys.stdout)

并得到:

document: 7   # < the 8th document

在上述所有情况下,都非常高效,甚至不需要对前面的 YAML 文档(也不是下面的)进行标记。

还有一个额外的警告,YAML 文件可能以 byte-order-marker 开头。 ,并且 individual documents within a stream可以从这些标记开始。上面的例程不能处理这个问题。

<小时/>

¹ 这是使用 ruamel.yaml 完成的我是其中的作者,它是 PyYAML 的增强版本。 AFAIK PyYAML 的工作方式相同(但例如会删除往返中的注释)。
² 从技术上讲,该指令有其自己的 directives document ,所以您应该将其算作文档,但 .load_all() 不会返回该文档,因此我不将其算作文档。

关于python - 从文件加载特定的 PyYAML 文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32493647/

相关文章:

python - 如何在pytest中打印到控制台?

从 YAML 传递数据连接 MYSQL 数据库时,Python 抛出 'ProgrammingError: 1045'

Python:如何强制 "print"使用 __unicode__ 而不是 __str__,或者自然地使用 "print"消息而不显式调用 unicode()

python - 没有名为 sql_server.pyodbc.base 的模块

python - 字符串变量的索引方法,在条件循环内,未返回所需的结果

Python Turtle 比较颜色

python - Anaconda 环境错误 - 访问被拒绝

python - 在 BeautifulSoup 中选择具有多个部件类的标签

php - 来自另一个键的 YAML 设置值

javascript - 如何在 YAML 文件中嵌套对象和数组?