在同一个文档中分离 YAML 和纯文本

Separate YAML and plain text on the same document

在使用 django 构建博客时,我意识到将文章的文本和所有相关信息(标题、作者等)一起存储在一个 human-readable 文件中非常实用格式,然后使用简单的脚本将这些文件记入数据库。

话虽如此,YAML 的可读性和易用性引起了我的注意,YAML 语法的唯一缺点是缩进:

---
title: Title of the article
author: Somebody
# Other stuffs here ...
text:| 
    This is the text of the article. I can write whatever I want
    but I need to be careful with the indentation...and this is a
    bit boring.
---

我认为这不是最佳解决方案(尤其是当文件将由临时用户编写时)。像这样的格式可能会好得多

---
title: Title of the article
author: Somebody
# Other stuffs here ...
---
Here there is the text of the article, it is not valid YAML but
just plain text. Here I could put **Markdown** or <html>...or whatever
I want...

有什么解决办法吗?最好使用 python。 也欢迎其他文件格式的建议!

我发现 Front Matter 做的正是我想做的。 还有a python package.

不幸的是,这是不可能的,人们认为可行的方法是在单独的文档中对单个标量使用 |

import ruamel.yaml

yaml_str = """\
title: Title of the article
author: Somebody
---
|
Here there is the text of the article, it is not valid YAML but
just plain text. Here I could put **Markdown** or <html>...or whatever
I want...
"""

for d in ruamel.yaml.load_all(yaml_str):
    print(d)
    print('-----')

但这不是因为 |block indentation indicator。尽管在顶层缩进 0(零)很容易工作,但 ruamel.yaml(和 PyYAML)不允许这样做。

然而,您自己解析它很容易,这比使用前端包的优势在于您可以使用 YAML 1.2,并且不限于使用 YAML 1.1,因为 frontmaker 使用 PyYAML。另请注意,我使用了更合适的文档结尾标记 ... 来将 YAML 与 markdown 分开:

import ruamel.yaml

combined_str = """\
title: Title of the article
author: Somebody
...
Here there is the text of the article, it is not valid YAML but
just plain text. Here I could put **Markdown** or <html>...or whatever
I want...
"""

with open('test.yaml', 'w') as fp:
    fp.write(combined_str)


data = None
lines = []
yaml_str = ""
with open('test.yaml') as fp:
    for line in fp:
        if data is not None:
            lines.append(line)
            continue
        if line == '...\n':
            data = ruamel.yaml.round_trip_load(yaml_str)
            continue
        yaml_str += line

print(data['author'])
print(lines[2])

给出:

Somebody
I want...

round_trip_load 允许转储并保留注释、锚名称等)。