Skip to main content
 首页 » 编程设计

python之我可以让 PyYAML 将一个 %TAG 指令应用于一个流中的多个文档吗

2025年05月04日9zhenyulu

我有一个像这样的 YAML 文件:

%YAML 1.1 
%TAG !x! tag:x.y,2013: 
--- !x!1 &1 
SomeThing: 
  member: 1 
--- !x!2 &2 
OtherThing: 
  inner: foo 

我不确定它是否合规,但它是由我无法控制的程序生成的。

我真的不关心将 'tag:x.y,2013:1' 转换成任何特定的类,所以我尝试像这样使用 PyYAML 的 BasicLoader:

import yaml 
import pprint 
 
with open("file.yaml", "r") as f: 
    items = yaml.load_all(f, Loader=yaml.loader.BasicLoader) 
    for item in items: 
        pprint.pprint(item) 

PyYAML 在到达第二个文档时抛出异常。

yaml.parser.ParserError: while parsing a node 
found undefined tag handle '!x!' 

有没有一种简单的方法可以让 PyYAML 完全忽略标签前缀,或者对流中的所有文档应用相同的 %TAG 指令?

请您参考如下方法:

这绝对是格式错误的 YAML——YAML 流中的每个文档都独立于前一个文档,并且可能在其上设置了不同的指令。不可否认,标准对此有点不清楚,尽管 Section 9.2声明:“请注意,[流中的] 每个文档都独立于其他文档,允许异构日志文件条目。”

看起来 Parser 类有一个 DEFAULT_TAGS 属性映射默认标记句柄:https://github.com/yaml/pyyaml/blob/master/lib/yaml/parser.py#L76

作为解决方法,您可以就地修改该字典 (Parser.DEFAULT_TAGS[u'!x!'] = u'tag:x.y,2013') 或者,也许更好,可能是子类化 Parser 基类并创建您自己的使用您的解析器的 Loader 类:

from yaml.parser import Parser 
from yaml.reader import Reader 
from yaml.scanner import Scanner 
from yaml.composer import Composer 
from yaml.constructor import Constructor 
from yaml.resolver import Resolver 
 
class MyWonkyParser(Parser): 
    DEFAULT_TAGS = {u'!x!': u'tag:x.y,2013'} 
    DEFAULT_TAGS.update(Parser.DEFAULT_TAGS) 
 
class MyWonkyLoader(Reader, Scanner MyWonkyParser, Composer, Constructor, Resolver): 
    def __init__(self, stream): 
        Reader.__init__(self, stream) 
        Scanner.__init__(self) 
        MyWonkyParser.__init__(self) 
        Composer.__init__(self) 
        Constructor.__init__(self) 
        Resolver.__init__(self) 

像这样使用它:

yaml.load_all(stream, Loader=MyWonkyLoader)