Dass Ihr Beispiel ungültig ist, liegt nur daran, dass Sie ein reserviertes Zeichen ausgewählt haben, mit dem Sie Ihre Skalare beginnen möchten. Wenn Sie das *
durch ein anderes nicht reserviertes Zeichen ersetzen (ich verwende dafür eher Nicht-ASCII-Zeichen, da diese selten als Teil einer Spezifikation verwendet werden), erhalten Sie eine vollkommen legale YAML:
paths:
root: /path/to/root/
patha: ♦root♦ + a
pathb: ♦root♦ + b
pathc: ♦root♦ + c
Dies wird in die Standarddarstellung für Zuordnungen in der von Ihrem Parser verwendeten Sprache geladen und erweitert nichts auf magische Weise.
Verwenden Sie dazu einen lokal standardmäßigen Objekttyp wie im folgenden Python-Programm:
# coding: utf-8
from __future__ import print_function
import ruamel.yaml as yaml
class Paths:
def __init__(self):
self.d = {}
def __repr__(self):
return repr(self.d).replace('ordereddict', 'Paths')
@staticmethod
def __yaml_in__(loader, data):
result = Paths()
loader.construct_mapping(data, result.d)
return result
@staticmethod
def __yaml_out__(dumper, self):
return dumper.represent_mapping('!Paths', self.d)
def __getitem__(self, key):
res = self.d[key]
return self.expand(res)
def expand(self, res):
try:
before, rest = res.split(u'♦', 1)
kw, rest = rest.split(u'♦ +', 1)
rest = rest.lstrip() # strip any spaces after "+"
# the lookup will throw the correct keyerror if kw is not found
# recursive call expand() on the tail if there are multiple
# parts to replace
return before + self.d[kw] + self.expand(rest)
except ValueError:
return res
yaml_str = """\
paths: !Paths
root: /path/to/root/
patha: ♦root♦ + a
pathb: ♦root♦ + b
pathc: ♦root♦ + c
"""
loader = yaml.RoundTripLoader
loader.add_constructor('!Paths', Paths.__yaml_in__)
paths = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)['paths']
for k in ['root', 'pathc']:
print(u'{} -> {}'.format(k, paths[k]))
welches gedruckt wird:
root -> /path/to/root/
pathc -> /path/to/root/c
Das Erweitern erfolgt im laufenden Betrieb und behandelt verschachtelte Definitionen. Sie müssen jedoch darauf achten, dass keine unendliche Rekursion aufgerufen wird.
Durch Angabe des Dumper können Sie die ursprüngliche YAML aufgrund der On-the-Fly-Erweiterung aus den geladenen Daten sichern:
dumper = yaml.RoundTripDumper
dumper.add_representer(Paths, Paths.__yaml_out__)
print(yaml.dump(paths, Dumper=dumper, allow_unicode=True))
Dadurch wird die Reihenfolge der Zuordnungsschlüssel geändert. Wenn das ein Problem ist, müssen Sie self.d
eine CommentedMap
(importiert von ruamel.yaml.comments.py
)