在Python中解析具有重复锚点的YAML

时间:2016-08-18 09:01:13

标签: python yaml

我刚刚开始使用YAML和Python,我试图在Python中解析包含锚点和别名的YAML。
在这个YAML中,我覆盖了锚点,使某些节点具有不同的值。

我的YAML的一个例子:

Some Colors: &some_colors
 color_primary: &color_primary "#112233FF"
 color_secondary: &color_secondary "#445566FF"

Element: &element
 color: *color_primary

Overwrite some colors: &overwrite_colors
 color_primary: &color_primary "#000000FF"

Another element: &another_element
 color: *color_primary

具有(在JSON中)的预期结果:

{
    "Some Colors": {
        "color_primary": "#112233FF",
        "color_secondary": "#445566FF"
    },
    "Element": {
        "color": "#112233FF"
    },
    "Overwrite some colors": {
        "color_primary": "#000000FF"
    },
    "Another element": {
        "color": "#000000FF"
    }
}
  

我测试了上面的YAML代码段here

从我在YAML文档中读到的内容;这应该可以从版本1.1(我认为),但至少YAML版本1.2应该支持它。

但是每当我尝试使用PyYAML(使用yaml.load())或ruamel,yaml包(使用ruamel.yaml.load())解析YAML时,我都会收到“重复锚点”错误。

我在这里做错了什么?以及如何解决这个问题?

修改

ruamel的所有者的帮助下,我找到了上述问题的解决方案。

ruamel v0.12.3起,上述内容按预期工作,但您将收到ReusedAnchorWarning。 可以使用以下代码段抑制这些警告:

import warnings
from ruamel.yaml.error import ReusedAnchorWarning

warnings.simplefilter("ignore", ReusedAnchorWarning)

给予应有的信用;所有这些都归ruamel的所有者所有。

作为一个补充问题;当我将上述YAML修改为时(注意// <-- Added this处的更改)

Some Colors: &some_colors
 color_primary: &color_primary "#112233FF"
 color_secondary: &color_secondary "#445566FF"

Element: &element
 color: *color_primary

Overwrite some colors: &overwrite_colors
 <<: *some_colors   // <-- Added this to include 'color_secondary' as well
 color_primary: &color_primary "#000000FF"

Another element: &another_element
 color: *color_primary

输出结果为:

{
    "Some Colors": {
        "color_primary": "#000000FF",
        "color_secondary": "#445566FF"
    },
    "Element": {
        "color": "#112233FF"
    },
    "Overwrite some colors": {
        "color_primary": "#000000FF",
        "color_secondary": "#445566FF"
    },
    "Another element": {
        "color": "#445566FF" // <-- Now the value is 'color_secondary' instead of 'color_primary'?
    }
}

为什么color的{​​{1}}会查看Another element的值?

有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:2)

首先,你没有做错任何事。 PyYAML在这里做错了。这很可能是因为倾倒具有相同名称的锚点将是PyYAML转储器的错误情况。如果你有一个自我引用的Python结构:

 a = dict(x=1)
 a['y'] = a

然后PyYAML(和ruamel.yaml)会为你创建一个唯一的锚名称。如果此名称不唯一,则取决于名称用作别名的位置。因此,怀疑任何重用的锚名称是有道理的,因为这可能指向YAML序列化代码中的错误,但它不符合规范(根据YAML 1.0规范重用已经没问题(3.2节)。 2.2))。

自2009年以来,python-yaml Debian模块的bug report存在,但我还没有发现它是否已经上传。

正如您所指出的,这在ruamel.yaml 0.12.3

中得到了解决

要回答你的第二个问题,那只是因为&#34; Best Online YAML Converter&#34;不是,并解析这个错误。如果合并行上有YAML注释,它甚至会抛出错误:

 <<: *some_colors   # <-- Added this to include 'color_secondary' as well

这在ruamel.yaml(0.12.3)中按预期解析:

import sys
import ruamel.yaml
import warnings
from ruamel.yaml.error import ReusedAnchorWarning
warnings.simplefilter("ignore", ReusedAnchorWarning)

yaml_str = """\
Some Colors: &some_colors
 color_primary: &color_primary "#112233FF"
 color_secondary: &color_secondary "#445566FF"

Element: &element
 color: *color_primary

Overwrite some colors: &overwrite_colors
 <<: *some_colors   # <-- Added this to include 'color_secondary' as well
 color_primary: &color_primary "#000000FF"

Another element: &another_element
 color: *color_primary
"""


data = ruamel.yaml.load(yaml_str)
ruamel.yaml.round_trip_dump(data, sys.stdout)

给出:

Some Colors:
  color_primary: '#112233FF'
  color_secondary: '#445566FF'
Overwrite some colors:
  color_primary: '#000000FF'
  color_secondary: '#445566FF'
Another element:
  color: '#000000FF'    # <- not #445566FF
Element:
  color: '#112233FF'

(手动添加评论)

答案 1 :(得分:0)

仅供参考:缺少上面的示例代码pure=True

yaml = ruamel.yaml.YAML(typ='safe', pure=True)
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)