В модуле YAML нет функций для доступа к брату или
родитель из sibling_constructor
, как это должно быть доступно через
параметр loader
или node
.
Параметр node
является экземпляром Node
и его
атрибуты tag
,
value
, start_mark
, end_mark
, comment
, anchor
не содержат контекстной информации (mark
s содержат указатели на источник
stream, comment
возможный комментарий конца строки в этой строке).
То, что параметр loader
не имеет этой информации, гораздо меньше
Понятно, что это гораздо более сложная структура данных. А то что ты наверное
не понимаю, что процесс строительства это глубина
во-первых, так ваш родитель не был построен, и поэтому есть
нет точки входа в структуру данных, загруженную из YAML, пока не будет обработан последний узел,
после чего его родитель может быть полностью создан, затем его родитель
и т.д., пока не закончится рекурсия и построенные данные не
функция load()
.
Но не вся надежда потеряна, если вы используете загрузчик туда и обратно по умолчанию, у вас есть доступ
к тегу без необходимости добавления конструктора, чтобы вы могли легко выполнить этап последующей обработки.
Предполагая, что ваш ввод находится в файле input.yaml
:
import sys
from pprint import pprint
from pathlib import Path
import ruamel.yaml
input_path = Path('input.yaml')
def sibling(d):
# recurse into a data structure loaded from YAML
if isinstance(d, dict):
for k, v in d.items():
try:
if v._yaml_tag.value == '!Sibling':
d[k] = d[v.value] + ' are dangerous.'
except (AttributeError, ):
pass
sibling(v)
elif isinstance(d, list):
for item in d:
sibling(item)
yaml = ruamel.yaml.YAML()
data = yaml.load(input_path)
sibling(data)
pprint(data)
print('-------')
yaml.dump(data, sys.stdout)
дает:
{'Thing': {'ParentThing': {'Child1': 'Fast cars',
'Child2': 'Slow cars',
'Child3': 'Fast cars are dangerous.'}}}
-------
Thing:
ParentThing:
Child1: Fast cars
Child2: Slow cars
Child3: Fast cars are dangerous.
Хотя можно зарегистрировать новый метод, который создает
отображение (construct_yaml_map
) и присоединяет dict
существо
созданный для экземпляра Constructor
, этот dict
, однако, получает
обновляется за один раз, когда все пары ключ / значение сопоставления были
Решили:
def construct_yaml_map(self, node):
data = self.yaml_base_dict_type() # type: Dict[Any, Any]
self._tw_current_dict = data
yield data
value = self.construct_mapping(node)
data.update(value)
ruamel.yaml.SafeConstructor.add_constructor(u'tag:yaml.org,2002:map', construct_yaml_map)
yaml.add_constructor('!Sibling', sibling_constructor, constructor=ruamel.yaml.SafeConstructor)
return yaml.safe_load(myFile)
, поэтому, когда вы добавите вышеприведенный код в ваш код и ваш sibling_constructor
будет называться loader._tw_current_dict
доступен, но пустой.
(Вы должны использовать SafeLoader
, нет необходимости делать все небезопасным, используя старый метод load
, унаследованный от PyYAML)
Возможно, вы сможете подключиться к construct_mapping
, я кратко попробовал
и застрял (и я утверждаю, что довольно хорошо знаком с исходным кодом модуля YAML).
Одна вещь, которую вы могли бы рассмотреть, это изменить ваш ввод YAML так:
Thing:
ParentThing:
Child1: &child Fast cars
Child2: Slow cars
Child3: !Sibling *child
т.е. используя нормальный механизм ссылок в YAML якорей и псевдонимов. Это псевдоним
*child
конечно можно разрешить в момент создания значения для Child3
.