Jak mogę dołączyć plik YAML do innego?
Więc mam dwa pliki YAML, "A" i "B" i chcę, aby zawartość A została wstawiona do B, albo spleciona z istniejącą strukturą danych, jak tablica, albo jako potomek elementu, jak wartość dla określonego klucza hashowego.
Czy to w ogóle możliwe? Jak? Jeśli nie, jakieś wskazówki do odniesienia normatywnego?
10 answers
Nie, YAML nie zawiera żadnych instrukcji" import "lub" include".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 16:39:30
Twoje pytanie nie pyta o rozwiązanie Pythona, ale tutaj jest jedno za pomocą PyYAML .
PyYAML pozwala na dołączanie niestandardowych konstruktorów (takich jak !include
) do ładowarki YAML. Dodałem katalog główny, który można ustawić tak, aby To rozwiązanie obsługiwało względne i bezwzględne odwołania do plików.
Rozwiązanie Klasy
Oto rozwiązanie oparte na klasach, które unika globalnej zmiennej głównej mojej pierwotnej odpowiedzi.
Zobacz to gist dla podobne, bardziej wytrzymałe rozwiązanie Python 3, które wykorzystuje metaclass do rejestracji niestandardowego konstruktora.
import yaml
import os.path
class Loader(yaml.SafeLoader):
def __init__(self, stream):
self._root = os.path.split(stream.name)[0]
super(Loader, self).__init__(stream)
def include(self, node):
filename = os.path.join(self._root, self.construct_scalar(node))
with open(filename, 'r') as f:
return yaml.load(f, Loader)
Loader.add_constructor('!include', Loader.include)
Przykład:
foo.yaml
a: 1
b:
- 1.43
- 543.55
c: !include bar.yaml
bar.yaml
- 3.6
- [1, 2, 3]
Teraz pliki można załadować używając:
>>> with open('foo.yaml', 'r') as f:
>>> data = yaml.load(f, Loader)
>>> data
{'a': 1, 'b': [1.43, 543.55], 'c': [3.6, [1, 2, 3]]}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 20:31:10
Jeśli używasz Symfony w wersji YAML , jest to możliwe, tak:
imports:
- { resource: sub-directory/file.yml }
- { resource: sub-directory/another-file.yml }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 15:12:57
Includes nie są obsługiwane bezpośrednio w yaml, o ile wiem, będziesz musiał sam dostarczyć mechanizm, jednak generalnie jest to łatwe do zrobienia.
Używałem yaml jako języka konfiguracyjnego w moich aplikacjach Pythona i w tym przypadku często definiuję konwencję w ten sposób:
>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]
Następnie w moim (pythonowym) kodzie robię:
import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
cfg.update(yaml.load(open(inc)))
Jedyną stroną w dół jest to, że zmienne w includes zawsze nadpisują zmienne w main i nie ma sposobu na zmianę tego pierwszeństwa przez zmiana miejsca, w którym w menu głównym pojawia się polecenie "includes:".plik yml.
W nieco innym punkcie, yaml nie obsługuje includes as its tak naprawdę nie zaprojektowany jako wyłącznie jako plik oparty na znacznikach. Co oznaczałoby include, jeśli otrzymałeś go w odpowiedzi na żądanie ajax?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-23 18:45:22
Rozszerzając odpowiedź @ Josh_Bode, oto moje własne rozwiązanie PyYAML, które ma tę zaletę, że jest samodzielną podklasą yaml.Loader
. Nie zależy to od jakichkolwiek globali na poziomie modułów, ani od modyfikacji globalnego stanu yaml
modułu.
import yaml, os
class IncludeLoader(yaml.Loader):
"""
yaml.Loader subclass handles "!include path/to/foo.yml" directives in config
files. When constructed with a file object, the root path for includes
defaults to the directory containing the file, otherwise to the current
working directory. In either case, the root path can be overridden by the
`root` keyword argument.
When an included file F contain its own !include directive, the path is
relative to F's location.
Example:
YAML file /home/frodo/one-ring.yml:
---
Name: The One Ring
Specials:
- resize-to-wearer
Effects:
- !include path/to/invisibility.yml
YAML file /home/frodo/path/to/invisibility.yml:
---
Name: invisibility
Message: Suddenly you disappear!
Loading:
data = IncludeLoader(open('/home/frodo/one-ring.yml', 'r')).get_data()
Result:
{'Effects': [{'Message': 'Suddenly you disappear!', 'Name':
'invisibility'}], 'Name': 'The One Ring', 'Specials':
['resize-to-wearer']}
"""
def __init__(self, *args, **kwargs):
super(IncludeLoader, self).__init__(*args, **kwargs)
self.add_constructor('!include', self._include)
if 'root' in kwargs:
self.root = kwargs['root']
elif isinstance(self.stream, file):
self.root = os.path.dirname(self.stream.name)
else:
self.root = os.path.curdir
def _include(self, loader, node):
oldRoot = self.root
filename = os.path.join(self.root, loader.construct_scalar(node))
self.root = os.path.dirname(filename)
data = yaml.load(open(filename, 'r'))
self.root = oldRoot
return data
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-05 19:11:09
Niestety YAML nie podaje tego w swoim standardzie.
Ale jeśli używasz Ruby, istnieje klejnot zapewniający funkcjonalność, o którą prosisz, rozszerzając bibliotekę Ruby YAML: https://github.com/entwanderer/yaml_extend
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-04 21:30:20
Myślę, że rozwiązanie zastosowane przez @ maxy-B wygląda świetnie. Nie udało mi się jednak z zagnieżdżonymi inkluzjami. Na przykład jeśli config_1.yaml zawiera config_2.yaml, który zawiera config_3.yaml był problem z ładowarką. Jeśli jednak po prostu skierujesz nową klasę ładowarki do siebie przy obciążeniu, to działa! W szczególności, jeśli zastąpimy starą funkcję _include bardzo nieznacznie zmodyfikowaną wersją:
def _include(self, loader, node):
oldRoot = self.root
filename = os.path.join(self.root, loader.construct_scalar(node))
self.root = os.path.dirname(filename)
data = yaml.load(open(filename, 'r'), loader = IncludeLoader)
self.root = oldRoot
return data
Po namyśle zgadzam się z innymi komentarzami, że zagnieżdżone ładowanie jest nie nadaje się do yaml w ogóle, ponieważ strumień wejściowy może nie być plikiem, ale jest bardzo przydatny!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-26 23:18:28
Z Symfony , jego obsługa yaml pośrednio pozwoli Ci zagnieżdżać pliki yaml. Sztuczka polega na wykorzystaniu opcji parameters
. eg:
Pospolite.yml
parameters:
yaml_to_repeat:
option: "value"
foo:
- "bar"
- "baz"
Config.yml
imports:
- { resource: common.yml }
whatever:
thing: "%yaml_to_repeat%"
other_thing: "%yaml_to_repeat%"
Wynik będzie taki sam jak:
whatever:
thing:
option: "value"
foo:
- "bar"
- "baz"
other_thing:
option: "value"
foo:
- "bar"
- "baz"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 04:07:59
Może to cię zainspiruje, spróbuj dostosować się do konwencji jbb:
Https://docs.openstack.org/infra/jenkins-job-builder/definition.html#inclusion-tags
- job:
name: test-job-include-raw-1
builders:
- shell:
!include-raw: include-raw001-hello-world.sh
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 09:05:43
Prawdopodobnie nie był obsługiwany podczas zadawania pytania, ale możesz zaimportować inny plik YAML do jednego:
imports: [/your_location_to_yaml_file/Util.area.yaml]
Chociaż nie mam żadnego odniesienia online, ale to działa dla mnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 17:27:07