Rằng ví dụ của bạn không hợp lệ chỉ vì bạn đã chọn một ký tự dành riêng để bắt đầu vô hướng. Nếu bạn thay thế *
bằng một số ký tự không dành riêng khác (tôi có xu hướng sử dụng các ký tự không phải ASCII cho chúng vì chúng hiếm khi được sử dụng như một phần của một số đặc điểm kỹ thuật), bạn sẽ kết thúc với YAML hoàn toàn hợp pháp:
paths:
root: /path/to/root/
patha: ♦root♦ + a
pathb: ♦root♦ + b
pathc: ♦root♦ + c
Điều này sẽ tải vào biểu diễn tiêu chuẩn cho ánh xạ trong ngôn ngữ mà trình phân tích cú pháp của bạn sử dụng và không mở rộng một cách kỳ diệu bất cứ điều gì.
Để làm điều đó, hãy sử dụng loại đối tượng mặc định cục bộ như trong chương trình Python sau:
# 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]))
sẽ in:
root -> /path/to/root/
pathc -> /path/to/root/c
Việc mở rộng được thực hiện nhanh chóng và xử lý các định nghĩa lồng nhau, nhưng bạn phải cẩn thận về việc không gọi đệ quy vô hạn.
Bằng cách chỉ định máy xúc lật, bạn có thể kết xuất YAML ban đầu từ dữ liệu được tải vào, do việc mở rộng nhanh chóng:
dumper = yaml.RoundTripDumper
dumper.add_representer(Paths, Paths.__yaml_out__)
print(yaml.dump(paths, Dumper=dumper, allow_unicode=True))
điều này sẽ thay đổi thứ tự khóa ánh xạ. Nếu đó là một vấn đề bạn cần phải thực hiện self.d
một CommentedMap
(nhập khẩu từ ruamel.yaml.comments.py
)