0

我有一个yaml带有引用的文件,并且想要读取该文件并创建对象。内容YAML-File由“消息”类和“信号”类组成。消息可以包含对选定信号的引用列表。什么是好方法?我目前会使用该from_yaml方法并解码YAML-line. 我已经尝试过使用两个类 Signal 和 Message 但似乎解析器需要另一种语法或其他东西。

ruamel.yaml.parser.ParserError:解析“input4.yaml”第 18 行第 6 列中的块集合时在“input4.yaml”第 18 行第 17 列中未找到预期的“-”指示符

什么可能是读取和解码文件的好方法。一种可能是忽略引用,使用“from_yaml”解析失败,然后在第二步中手动将引用放在一起,但也许有更好的方法。

附上yaml-File

# input4.yaml
- !Signal  &Signal1
 Name: AO1
 Length: 3

- !Signal  &Signal2
 Name: AO2
 Length: 4

- !Signal  &Signal3
 Name: AO3
 Length: 4

- !Message
   Name: Message1
   Value: 122
   Signals:
 - !Signal  *Signal1
 - !Signal  *Signal2

- !Message
   Name: Message2
   Value: 123
   Signals:
- !Signal  *Signal1
- !Signal  *Signal2
- !Signal  *Signal3

我的 phyton 程序看起来像

import ruamel.yaml

class Signal:
    def __init__(self, name=None, Length=None):
        self.name = name
        self.Length = Length


    @classmethod
    def from_yaml(cls, constructor, node):
        for m in constructor.construct_yaml_map(node):
            pass
        return cls(m['Name'], m['Length'])

    def __repr__(self):
        return 'Signal(name={.name}, Length={.Length})'.format(self, self)



class Message:
    def __init__(self, name=None, DLC=None, object=None, signals=None):
        self.name = name
        self.dlc = DLC
        self.signals = [] if signals is None else signals

    @classmethod
    def from_yaml(cls, constructor, node):
        for m in constructor.construct_yaml_map(node):
            pass
        if 'Name' in m:
            name = m['Name']
        elif 'name' in m:
            name = m['name']
        else:
            name = None
        object = m['object'] if 'object' in m else None
        if 'DLC' in m:
            dlc = m['DLC']
        else:
            dlc = None
        if 'Signals' in m:
             signals = m['Signals']
        else:
             signals = None
        return cls(name, dlc, object, signals)
        #return cls(name, dlc, object, signals)

    def __repr__(self):
        return 'Message(name={}, DLC={}, signals{})'.format(
            self.name, self.dlc, self.object, '[...]' if self.signals else '[]'
        )


yaml = ruamel.yaml.YAML(typ='safe')
yaml.register_class(Message)
yaml.register_class(Signal)
with open('input4.yaml') as fp:
    data = yaml.load(fp)

print(len(data))
for m in data:
    if isinstance(m, Message):
        print("Message: ", m.name)
        if Message(m).signals is not None:
            for l in m.signals:
                if isinstance(l, Signal):
                    print("Signal: ", l.name)

print("finish")
4

1 回答 1

0

您的 YAML 有两个问题:

1)您应该正确缩进所有内容:第 18 行和第 19 行需要再缩进两个空格才能使序列计为 key 的值Signals,并且出于同样的原因,第 25-27 行需要再缩进 4 个空格。

2) 你可以写!Signal&Signal1 , but IMHO it is more clear to write&Signal1 !Signal . The effect is the same: you get an anchor for a "!Signal type". I.e. the type information is "included" in the anchorSignal1` 并且不要在别名中重复。

以下内容input4.yaml与您的程序一起加载而不会出错:

# input4.yaml
- &Signal1 !Signal
 Name: AO1
 Length: 3

- !Signal  &Signal2
 Name: AO2
 Length: 4

- !Signal  &Signal3
 Name: AO3
 Length: 4

- !Message
   Name: Message1
   Value: 122
   Signals:
   - *Signal1
   - *Signal2

- !Message
   Name: Message2
   Value: 123
   Signals:
   - *Signal1
   - *Signal2
   - *Signal3

顺便说一句,它是 Python 而不是 Phyton(我已经在您的问题中更新了两次,您应该查看人们对您的帖子所做的编辑,并从中学习)。

于 2018-03-04T12:10:25.847 回答