如何使用 ruamel.yaml read/write markdown yaml frontmatter?
How do I read/write markdown yaml frontmatter with ruamel.yaml?
我想使用Python在markdown文件中读写YAML frontmatter。我遇到了 ruamel.yaml 包,但我无法理解如何将其用于此目的。
如果我有降价文件:
---
car:
make: Toyota
model: Camry
---
# My Ultimate Car Review
This is a good car.
首先,有没有办法在我的 python 代码中将 yaml 数据设置为变量?
其次,有没有办法给markdown文件中的yaml设置新的值?
第一个,我试过:
from ruamel.yaml import YAML
import sys
f = open("cars.txt", "r+") # I'm really not sure if r+ is ideal here.
yaml = YAML()
code = yaml.load(f)
print(code['car']['make'])
但出现错误:
ruamel.yaml.composer.ComposerError: expected a single document in the stream
in "cars.txt", line 2, column 1
but found another document
in "cars.txt", line 5, column 1
第二个,我试过:
from ruamel.yaml import YAML
import sys
f = open("cars.txt", "r+") # I'm really not sure if r+ is ideal here.
yaml = YAML()
code = yaml.load(f)
code['car']['model'] = 'Sequoia'
却得到同样的错误error:
ruamel.yaml.composer.ComposerError: expected a single document in the stream
in "cars.txt", line 2, column 1
but found another document
in "cars.txt", line 5, column 1
当你在一个文件中有多个 YAML 文档时,这些文件用一行分隔
三个破折号,或以三个破折号开头,后跟 space。
大多数 YAML 解析器,包括 ruamel.yaml
要么期望单个文档文件(使用 YAML().load()
时)
或多文档文件(使用 YAML().load_all()
时)。
方法.load()
returns单一的数据结构,如果好像不止一个就报错
文档(即当它遇到文件中的第二个 ---
时)。这
.load_all()
方法可以处理一个或多个 YAML 文档,但总是 returns
一个迭代器。
您的输入恰好是一个有效的多文档 YAML 文件,但降价部分通常使情况并非如此。它很容易可以
只需将第二个 ---
更改为 --- |
从而使 YAML 始终有效
降价部分(多行)文字标量字符串。我不知道为什么
这种 YAML frontmatter 格式的设计者没有具体说明,它可能必须
做一些解析器(如 PyYAML)无法解析这种非缩进文字标量
根级别的字符串正确,尽管这些示例在 YAML 中
规范.
在你的例子中,降价部分非常简单,它是有效的 YAML,没有
必须为文字标量字符串指定 |
。所以你可以使用
.load_all()
在此输入上。但只是添加例如一条线
以破折号开头的降价部分,将导致无效的 YAML
文件,所以如果你使用 .load_all()
,你必须确保你
不要迭代到解析第二个文档:
import sys
from pathlib import Path
import ruamel.yaml
path = Path('cars.txt')
yaml = ruamel.yaml.YAML()
for data in yaml.load_all(path):
break
print(data['car']['make'])
给出:
Toyota
但是你不应该尝试更新文件(所以不要使用 r+
),因为你的 YAML frontmatter 可能是
比原来的和更新的时间长,更新会覆盖你的降价。为了
更新,将文件读入内存,根据第二行分成两部分
破折号,更新数据,转储它并附加破折号和降价:
import sys
from pathlib import Path
import ruamel.yaml
path = Path('cars.txt')
opath = Path('cars_out.txt')
yaml_str, markdown = path.read_text().lstrip().split('\n---', 1)
yaml_str += '\n' # re-add the trailing newline that was split off
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True
data = yaml.load(yaml_str)
data['car']['year'] = 2003
with opath.open('w') as fp:
yaml.dump(data, fp)
fp.write('---')
fp.write(markdown)
sys.stdout.write(opath.read_text())
给出:
---
car:
make: Toyota
model: Camry
year: 2003
---
# My Ultimate Car Review
This is a good car.
我想使用Python在markdown文件中读写YAML frontmatter。我遇到了 ruamel.yaml 包,但我无法理解如何将其用于此目的。
如果我有降价文件:
---
car:
make: Toyota
model: Camry
---
# My Ultimate Car Review
This is a good car.
首先,有没有办法在我的 python 代码中将 yaml 数据设置为变量?
其次,有没有办法给markdown文件中的yaml设置新的值?
第一个,我试过:
from ruamel.yaml import YAML
import sys
f = open("cars.txt", "r+") # I'm really not sure if r+ is ideal here.
yaml = YAML()
code = yaml.load(f)
print(code['car']['make'])
但出现错误:
ruamel.yaml.composer.ComposerError: expected a single document in the stream
in "cars.txt", line 2, column 1
but found another document
in "cars.txt", line 5, column 1
第二个,我试过:
from ruamel.yaml import YAML
import sys
f = open("cars.txt", "r+") # I'm really not sure if r+ is ideal here.
yaml = YAML()
code = yaml.load(f)
code['car']['model'] = 'Sequoia'
却得到同样的错误error:
ruamel.yaml.composer.ComposerError: expected a single document in the stream
in "cars.txt", line 2, column 1
but found another document
in "cars.txt", line 5, column 1
当你在一个文件中有多个 YAML 文档时,这些文件用一行分隔
三个破折号,或以三个破折号开头,后跟 space。
大多数 YAML 解析器,包括 ruamel.yaml
要么期望单个文档文件(使用 YAML().load()
时)
或多文档文件(使用 YAML().load_all()
时)。
方法.load()
returns单一的数据结构,如果好像不止一个就报错
文档(即当它遇到文件中的第二个 ---
时)。这
.load_all()
方法可以处理一个或多个 YAML 文档,但总是 returns
一个迭代器。
您的输入恰好是一个有效的多文档 YAML 文件,但降价部分通常使情况并非如此。它很容易可以
只需将第二个 ---
更改为 --- |
从而使 YAML 始终有效
降价部分(多行)文字标量字符串。我不知道为什么
这种 YAML frontmatter 格式的设计者没有具体说明,它可能必须
做一些解析器(如 PyYAML)无法解析这种非缩进文字标量
根级别的字符串正确,尽管这些示例在 YAML 中
规范.
在你的例子中,降价部分非常简单,它是有效的 YAML,没有
必须为文字标量字符串指定 |
。所以你可以使用
.load_all()
在此输入上。但只是添加例如一条线
以破折号开头的降价部分,将导致无效的 YAML
文件,所以如果你使用 .load_all()
,你必须确保你
不要迭代到解析第二个文档:
import sys
from pathlib import Path
import ruamel.yaml
path = Path('cars.txt')
yaml = ruamel.yaml.YAML()
for data in yaml.load_all(path):
break
print(data['car']['make'])
给出:
Toyota
但是你不应该尝试更新文件(所以不要使用 r+
),因为你的 YAML frontmatter 可能是
比原来的和更新的时间长,更新会覆盖你的降价。为了
更新,将文件读入内存,根据第二行分成两部分
破折号,更新数据,转储它并附加破折号和降价:
import sys
from pathlib import Path
import ruamel.yaml
path = Path('cars.txt')
opath = Path('cars_out.txt')
yaml_str, markdown = path.read_text().lstrip().split('\n---', 1)
yaml_str += '\n' # re-add the trailing newline that was split off
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True
data = yaml.load(yaml_str)
data['car']['year'] = 2003
with opath.open('w') as fp:
yaml.dump(data, fp)
fp.write('---')
fp.write(markdown)
sys.stdout.write(opath.read_text())
给出:
---
car:
make: Toyota
model: Camry
year: 2003
---
# My Ultimate Car Review
This is a good car.