Więc wiem, że mogę zrobić coś takiego:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
I mają sitelist
i anotherlist
oba zawierają www.foo.com
i www.bar.com
. Jednak naprawdę chcę, anotherlist
aby zawierał równieżwww.baz.com
, bez konieczności powtarzania www.foo.com
i www.baz.com
.
W ten sposób otrzymuję błąd składni w parserze YAML:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
- www.baz.com
Samo użycie kotwic i aliasów wydaje się niemożliwe, aby zrobić to, co chcę, bez dodania kolejnego poziomu podstruktury, na przykład:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist:
- *sites
- www.baz.com
Co oznacza, że konsument tego pliku YAML musi być tego świadomy.
Czy istnieje czysty sposób YAML na zrobienie czegoś takiego? A może będę musiał użyć przetwarzania post-YAML, takiego jak zaimplementowanie zastępowania zmiennych lub automatyczne podnoszenie niektórych rodzajów podstruktury? Robię już tego rodzaju przetwarzanie końcowe, aby obsłużyć kilka innych przypadków użycia, więc nie jestem do tego całkowicie przeciwny. Ale moje pliki YAML będą pisane przez ludzi, a nie generowane maszynowo, więc poza standardową składnią YAML chciałbym zminimalizować liczbę reguł, które muszą być zapamiętane przez moich użytkowników.
Chciałbym również móc zrobić analogiczną rzecz z mapami:
namedsites: &sites
Foo: www.foo.com
Bar: www.bar.com
moresites: *sites
Baz: www.baz.com
Przeszukałem specyfikację YAML i nie mogłem niczego znaleźć, więc podejrzewam, że odpowiedź brzmi „nie, nie możesz tego zrobić”. Ale jeśli ktoś ma jakieś pomysły, byłoby świetnie.
EDYCJA: Ponieważ nie było odpowiedzi, przypuszczam, że nikt nie zauważył niczego, czego nie mam w specyfikacji YAML i że nie można tego zrobić w warstwie YAML. Otwieram więc pytanie od pomysłu na przetwarzanie końcowe YAML, aby pomóc w tym, na wypadek, gdyby ktoś znalazł to pytanie w przyszłości.
Odpowiedzi:
Typ klucza scalania jest prawdopodobnie tym, czego potrzebujesz. Używa specjalnego
<<
klucza mapowania do wskazywania połączeń, umożliwiając użycie aliasu do mapowania (lub sekwencji takich aliasów) jako inicjatora do scalenia w jedno mapowanie. Ponadto nadal możesz jawnie zastąpić wartości lub dodać więcej, których nie było na liście scalania.Należy zauważyć, że jako pierwszy przykład działa to z odwzorowaniami, a nie sekwencjami. Ma to sens, kiedy się nad tym zastanowić, a Twój przykład wygląda na to, że prawdopodobnie i tak nie musi być sekwencyjny. Po prostu zmiana wartości sekwencji na klucze mapujące powinna załatwić sprawę, jak w następującym (nieprzetestowanym) przykładzie:
sitelist: &sites ? www.foo.com # "www.foo.com" is the key, the value is null ? www.bar.com anotherlist: << : *sites # merge *sites into this mapping ? www.baz.com # add extra stuff
Kilka rzeczy do zauważenia. Po pierwsze, ponieważ
<<
jest to klucz, można go określić tylko raz na węzeł. Po drugie, gdy jako wartość używamy sekwencji, kolejność jest znacząca. W tym przykładzie nie ma to znaczenia, ponieważ nie ma powiązanych wartości, ale warto o tym pamiętać.źródło
yaml.load(...)
w Pythonie, otrzymuję słownik jako reprezentację mapowania YAML. Tak, łatwo jest przetworzyć to w zestawie, ale muszę wiedzieć, że tak się stało (a semantyczna złożoność podczas odczytu / zapisu plików konfiguracyjnych jest znacznie większa, jeśli reguła brzmi: „zestawy są zapisywane jako mapy z wartościami null” ). Biorąc pod uwagę, że potrzebuję przetwarzania końcowego międzyyaml.load(...)
danymi wynikowymi i korzystania z nich, niezależnie od tego, czy używam,<<
czyMERGE
prawdopodobnie będę się trzymaćMERGE
(które już zaimplementowałem).!!set
działa. Zbyt wiele niejasnych schematów. Pliki te są przystosowane do odczytu / zapisu przez ludzi, którzy niekoniecznie są ekspertami od YAML. Ludzie będą zapisywać swoje listy witryn jako listy YAML, a następnie będą chcieli je scalić i przekonwertować całość na zestaw ORAZ pamiętaj, aby wyraźnie oznaczyć go jako zestaw ... Mam kilka innych ustandaryzowanych post- przetwarzanie rzeczy razem zMERGE
tak czy inaczej. Ale dzięki za pomoc!Jak wskazywały poprzednie odpowiedzi, nie ma wbudowanej obsługi rozszerzania list w YAML. Oferuję jeszcze jeden sposób na samodzielne wdrożenie. Rozważ to:
defaults: &defaults sites: - www.foo.com - www.bar.com setup1: <<: *defaults sites+: - www.baz.com
Zostanie to przetworzone na:
defaults: sites: - www.foo.com - www.bar.com setup1: sites: - www.foo.com - www.bar.com - www.baz.com
Chodzi o to, aby połączyć zawartość klucza zakończonego znakiem „+” z odpowiadającym mu kluczem bez „+”. Zaimplementowałem to w Pythonie i opublikowałem tutaj .
Cieszyć się!
źródło
sites
isites+
. Mam na myśli narzędzie, które musi zaimplementować użytkownik, bo nie jest toyaml
zachowanie domyślne ?(Odpowiadając na moje własne pytanie na wypadek, gdyby rozwiązanie, którego używam, było przydatne dla każdego, kto będzie szukał tego w przyszłości)
Ponieważ nie można tego zrobić w czystym YAML, zaimplementuję to jako „transformację składni” znajdującą się pomiędzy parserem YAML a kodem, który faktycznie używa pliku konfiguracyjnego. Tak więc moja podstawowa aplikacja nie musi w ogóle martwić się o żadne przyjazne dla człowieka środki zapobiegające redundancji i może po prostu działać bezpośrednio na wynikowych strukturach.
Struktura, której zamierzam użyć, wygląda następująco:
foo: MERGE: - - a - b - c - - 1 - 2 - 3
Który zostałby przekształcony w odpowiednik:
foo: - a - b - c - 1 - 2 - 3
Lub z mapami:
foo: MERGE: - fork: a spoon: b knife: c - cup: 1 mug: 2 glass: 3
Zostanie przekształcony w:
foo: fork: a spoon: b knife: c cup: 1 mug: 2 glass: 3
Bardziej formalnie, po wywołaniu parsera YAML w celu pobrania obiektów natywnych z pliku konfiguracyjnego, ale przed przekazaniem obiektów do reszty aplikacji, moja aplikacja przejdzie po grafie obiektów w poszukiwaniu mapowań zawierających pojedynczy klucz
MERGE
. Wartość skojarzona zMERGE
musi być listą list lub listą map; każda inna podkonstrukcja jest błędem.W przypadku list-of-list cała mapa zawierająca
MERGE
zostanie zastąpiona listami podrzędnymi połączonymi razem w kolejności, w jakiej się pojawiły.W przypadku listy map cała mapa zawierająca
MERGE
zostanie zastąpiona przez jedną mapę zawierającą wszystkie pary klucz / wartość w mapach potomnych. Tam, gdzie klucze nakładają się,MERGE
zostanie użyta wartość z mapy podrzędnej występująca jako ostatnia na liście.Podane powyżej przykłady nie są zbyt użyteczne, ponieważ można było napisać bezpośrednio żądaną strukturę. Bardziej prawdopodobne jest, że pojawi się jako:
foo: MERGE: - *salt - *pepper
Umożliwiając tworzenie listy lub mapy zawierającej wszystko w węzłach
salt
ipepper
używanej w innym miejscu.(Nadal podaję tę
foo:
zewnętrzną mapę, aby pokazać, żeMERGE
musi to być jedyny klucz w jej mapowaniu, co oznacza, żeMERGE
nie może pojawić się jako nazwa najwyższego poziomu, chyba że nie ma innych nazw najwyższego poziomu)źródło
Aby wyjaśnić coś z dwóch odpowiedzi tutaj, nie jest to obsługiwane bezpośrednio w YAML dla list (ale jest obsługiwane w przypadku słowników, zobacz odpowiedź Kittemona).
źródło
Aby odeprzeć odpowiedź Kittemona, zauważ, że możesz tworzyć mapowania z wartościami null przy użyciu alternatywnej składni
foo: << : myanchor bar: baz:
zamiast sugerowanej składni
foo: << : myanchor ? bar ? baz
Podobnie jak w przypadku sugestii Kittemona, pozwoli to na użycie odniesień do kotwic w mapowaniu i uniknięcie problemu z sekwencją. Musiałem to zrobić po odkryciu, że komponent Symfony Yaml v2.4.4 nie rozpoznaje
? bar
składni.źródło
myanchor
wygląda