Votre exemple n'est pas valide uniquement parce que vous avez choisi un caractère réservé pour commencer vos scalaires. Si vous remplacez le *
par un autre caractère non réservé (j'ai tendance à utiliser des caractères non ASCII pour cela car ils sont rarement utilisés dans le cadre de certaines spécifications), vous vous retrouvez avec un YAML parfaitement légal:
paths:
root: /path/to/root/
patha: ♦root♦ + a
pathb: ♦root♦ + b
pathc: ♦root♦ + c
Cela se chargera dans la représentation standard des mappages dans le langage utilisé par votre parseur et n'étend rien par magie.
Pour ce faire, utilisez un type d'objet par défaut localement comme dans le programme Python suivant:
# 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]))
qui imprimera:
root -> /path/to/root/
pathc -> /path/to/root/c
Le développement se fait à la volée et gère les définitions imbriquées, mais vous devez faire attention à ne pas invoquer une récursivité infinie.
En spécifiant le dumper, vous pouvez vider le YAML d'origine à partir des données chargées, en raison de l'extension à la volée:
dumper = yaml.RoundTripDumper
dumper.add_representer(Paths, Paths.__yaml_out__)
print(yaml.dump(paths, Dumper=dumper, allow_unicode=True))
cela changera l'ordre des clés de mappage. Si cela pose un problème, vous devez créer self.d
un CommentedMap
(importé de ruamel.yaml.comments.py
)