如何使用 ruamel.yaml 读/写 Markdown yaml frontmatter?

如何解决如何使用 ruamel.yaml 读/写 Markdown yaml frontmatter?

我想用Python来读写markdown文件中的YAML frontmatter。我遇到了 ruamel.yaml 包,但无法理解如何为此目的使用它。

如果我有一个 markdown 文件

---
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'

但得到同样的错误错误

ruamel.yaml.composer.ComposerError: expected a single document in the stream
  in "cars.txt",column 1

解决方法

当您在一个文件中有多个 YAML 文档时,这些文档会用一行分隔: 三个破折号,或以三个破折号开头,后跟一个空格。 大多数 YAML 解析器,包括 ruamel.yaml 要么期望单个文档文件(使用 YAML().load() 时) 或多文档文件(使用 YAML().load_all() 时)。

方法 .load() 返回单个数据结构,如果似乎有多个,则会报错 文档(即当它遇到文件中的第二个 --- 时)。这 .load_all() 方法可以处理一个或多个 YAML 文档,但总是返回 一个迭代器。

您的输入恰好是一个有效的多文档 YAML 文件,但 Markdown 部分通常使情况并非如此。很容易就能 通过将第二个 --- 更改为 --- | 从而使 降价部分(多行)文字标量字符串。我不知道为什么 这种 YAML frontmatter 格式的设计者没有指定,它可能必须 这样做一些解析器(如 PyYAML)无法解析这种非缩进的文字标量 根级别的字符串正确,尽管这些示例在 YAML 中 规范。

在你的例子中,markdown 部分非常简单,它是有效的 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 前端可能是 比原来更长,并且更新会覆盖您的降价。为了 更新,将文件读入内存,根据第二行分成两部分 破折号,更新数据,转储它并附加破折号和降价:

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.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?