简体   繁体   中英

Serialize YAML with references in Python and ruamel.yaml

I have a yaml file with references and want to read the file and create objects. The content of the YAML-File consists of class "Message" and class "Signal". A Message can hold a list of references to selected Signals. What would be a good approach? I currently would use the from_yaml method and decode the YAML-line . I already tried with two classes Signal and Message but it seems that the parser expects either another syntax or something else.

ruamel.yaml.parser.ParserError: while parsing a block collection in "input4.yaml", line 18, column 6 did not find expected '-' indicator in "input4.yaml", line 18, column 17

What could be a good approach for reading and decoding the file. One could be to ignore the reference, parse the fail with "from_yaml" and in a second step to put the references together manually but maybe there is a better way.

Attached the 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 

My phyton program looks like

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")

There are two problems with your YAML:

1) You should properly indent everything: line 18 and 19 need to be indented two spaces more for the sequence to count as value for key Signals , and lines 25-27 need to be indented 4 spaces more for the same reason.

2) You can write !Signal &Signal1 , but IMHO it is more clear to write &Signal1 !Signal . The effect is the same: you get an anchor for a " . The effect is the same: you get an anchor for a " !Signal type". Ie the type information is "included" in the anchor type". Ie the type information is "included" in the anchor Signal1` and should not be repeated in the alias.

The following input4.yaml loads with your program without error:

# 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

BTW it is Python and not Phyton (which I updated already twice in your questions, you should review edits people make to your posts, and learn from them).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM