Gibt es eine YAML-Syntax zum Teilen eines Teils einer Liste oder Karte?

94

Ich weiß also, dass ich so etwas tun kann:

sitelist: &sites
  - www.foo.com
  - www.bar.com

anotherlist: *sites

Und haben sitelistund anotherlistbeide enthalten www.foo.comund www.bar.com. Was ich aber wirklich will, ist anotherlist, auch zu enthalten www.baz.com, ohne wiederholen zu müssen www.foo.comund www.baz.com.

Dadurch erhalte ich einen Syntaxfehler im YAML-Parser:

sitelist: &sites
  - www.foo.com
  - www.bar.com

anotherlist: *sites
  - www.baz.com

Nur mit Ankern und Aliasnamen scheint es nicht möglich zu sein, das zu tun, was ich will, ohne eine weitere Ebene der Unterstruktur hinzuzufügen, wie zum Beispiel:

sitelist: &sites
  - www.foo.com
  - www.bar.com

anotherlist:
  - *sites
  - www.baz.com

Dies bedeutet, dass der Verbraucher dieser YAML-Datei sich dessen bewusst sein muss.

Gibt es eine reine YAML-Methode, um so etwas zu tun? Oder muss ich eine Post-YAML-Verarbeitung verwenden, z. B. das Implementieren einer Variablensubstitution oder das automatische Aufheben bestimmter Arten von Substrukturen? Ich mache bereits diese Art der Nachbearbeitung, um ein paar andere Anwendungsfälle zu behandeln, also bin ich nicht ganz abgeneigt. Aber meine YAML-Dateien werden von Menschen geschrieben und nicht maschinengeneriert. Daher möchte ich die Anzahl der Regeln minimieren, die meine Benutzer zusätzlich zur Standard-YAML-Syntax speichern müssen.

Ich möchte auch in der Lage sein, das Analoge mit Karten zu tun:

namedsites: &sites
  Foo: www.foo.com
  Bar: www.bar.com

moresites: *sites
  Baz: www.baz.com

Ich habe die YAML-Spezifikation durchsucht und konnte nichts finden. Daher vermute ich, dass die Antwort nur "Nein, das können Sie nicht" lautet. Aber wenn jemand irgendwelche Ideen hat, wäre das großartig.


EDIT: Da es keine Antworten gab, gehe ich davon aus, dass niemand etwas entdeckt hat, was ich nicht in der YAML-Spezifikation habe, und dass dies auf der YAML-Ebene nicht möglich ist. Daher öffne ich die Frage für die Idee, die YAML nachzubearbeiten, um dies zu unterstützen, falls jemand diese Frage in Zukunft findet.

Ben
quelle
Hinweis: Dieses Problem kann auch bei der Standardverwendung von Ankern und Aliasen in YAML behoben werden. Siehe auch: Wie füge ich YAML-Arrays zusammen?
Dreftymac

Antworten:

53

Der Typ des Zusammenführungsschlüssels ist wahrscheinlich das, was Sie wollen. Es verwendet einen speziellen <<Zuordnungsschlüssel, um Zusammenführungen anzuzeigen, sodass ein Alias ​​für eine Zuordnung (oder eine Folge solcher Aliase) als Initialisierer für die Zusammenführung zu einer einzelnen Zuordnung verwendet werden kann. Darüber hinaus können Sie weiterhin Werte explizit überschreiben oder weitere hinzufügen, die nicht in der Zusammenführungsliste enthalten waren.

Es ist wichtig zu beachten, dass es mit Zuordnungen funktioniert, nicht mit Sequenzen als erstes Beispiel. Dies ist sinnvoll, wenn Sie darüber nachdenken, und Ihr Beispiel sieht so aus, als müsste es wahrscheinlich sowieso nicht sequentiell sein. Das Ändern Ihrer Sequenzwerte in Zuordnungsschlüssel sollte den Trick tun, wie im folgenden (nicht getesteten) Beispiel:

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

Einige Dinge zu beachten. Erstens kann <<ein Schlüssel nur einmal pro Knoten angegeben werden , da er ein Schlüssel ist. Zweitens ist bei Verwendung einer Sequenz als Wert die Reihenfolge von Bedeutung. Dies spielt im Beispiel hier keine Rolle, da keine Werte zugeordnet sind, aber es lohnt sich, sich dessen bewusst zu sein.

Kittemon
quelle
Ah, Danke! Das ist ziemlich hilfreich. Es ist eine Schande, dass es für Sequenzen nicht funktioniert. Sie haben Recht, dass die Reihenfolge für dieses Beispiel nicht wichtig ist. Was ich habe, ist konzeptionell eine Menge, aber das ist einer Sequenz viel näher als einer Abbildung. Und die Struktur dessen, was ich daraus mache, ist wichtig (weshalb ich nicht einfach eine weitere Verschachtelungsebene hinzufügen wollte, um meine Strukturen zusammenzuführen), sodass eine Zuordnung, für die ich die (alle Null-) Werte ignorieren muss, nicht funktioniert funktioniert nicht wirklich.
Ben
3
Ich sehe nichts darauf in der aktuellen offiziellen YAML-Spezifikation: yaml.org/spec/1.2/spec.html . Diese Seite enthält weder das Wort "Zusammenführen" noch den Text "<<" oder den Ausdruck "Schlüsseltyp". Die << -Syntax funktioniert jedoch im Python-Yaml-Paket. Wissen Sie, wo ich mehr über diese Art von zusätzlichen Funktionen erfahren kann?
Ben
1
Es ist nicht direkt in der Spezifikation, sondern im Tag-Repository beschrieben. Andere Schemata haben eine allgemeine Beschreibung und einen Link. Neben Zusammenführungsschlüsseln gibt es auch Sätze und geordnete Sätze; YAML betrachtet Mengen jedoch als eine Art Zuordnung (z. B. könnte das obige Beispiel als Menge implementiert werden). Können Sie in Ihrer Sprache Schlüssel mit Werten in der resultierenden Zuordnung austauschen? Selbst wenn Sie das selbst implementieren müssen, denke ich, dass es sauberer wäre; Sie hätten zumindest alle Daten bereits gruppiert, und Ihre YAML wäre Standard.
Kittemon
Sets sind jedoch keine Zuordnungen. Ein Mapping ist eine Reihe von Schlüsselwertzuordnungen. Wenn ich yaml.load(...)in Python bin, bekomme ich ein Wörterbuch als Darstellung einer YAML-Zuordnung. Ja, es ist einfach, das in eine Menge nachzubearbeiten, aber ich muss wissen, dass dies passiert ist (und die semantische Komplexität beim Lesen / Schreiben der Konfigurationsdateien ist viel höher, wenn die Regel lautet: "Mengen werden als Karten mit Nullwerten geschrieben". ). Da ich eine Nachbearbeitung zwischen yaml.load(...)und Verwendung der resultierenden Daten benötige, ob ich <<oder verwende MERGE, bleibe ich wahrscheinlich bei MERGE(was ich jetzt bereits implementiert habe).
Ben
2
Ja, ich habe festgestellt, dass das !!setfunktioniert. Zu viel obskures Boilerplate. Diese Dateien sind für Personen, die nicht unbedingt YAML-Experten sind, lesbar / lesbar. Die Leute werden ihre Site-Listen als YAML-Listen aufschreiben, sie dann zusammenführen und das Ganze in ein Set konvertieren müssen UND daran denken, es explizit als Set zu kennzeichnen ... Ich habe ein paar andere standardisierte Post- Dinge zusammen mit MERGEsowieso verarbeiten. Vielen Dank für Ihre Hilfe!
Ben
16

Wie die vorherigen Antworten gezeigt haben, gibt es keine integrierte Unterstützung für das Erweitern von Listen in YAML. Ich biete noch eine andere Möglichkeit, es selbst umzusetzen. Bedenken Sie:

defaults: &defaults
  sites:
    - www.foo.com
    - www.bar.com

setup1:
  <<: *defaults
  sites+:
    - www.baz.com

Dies wird verarbeitet in:

defaults:
  sites:
    - www.foo.com
    - www.bar.com

setup1:
  sites:
    - www.foo.com
    - www.bar.com
    - www.baz.com

Die Idee ist, den Inhalt eines Schlüssels, der mit einem '+' endet, mit dem entsprechenden Schlüssel ohne ein '+' zusammenzuführen. Ich habe dies in Python implementiert und hier veröffentlicht .

Genießen!

Alexander Ryzhov
quelle
2
Hinweis: Dieses Problem kann auch bei der Standardverwendung von Ankern und Aliasen in YAML behoben werden. Siehe auch: Wie füge ich YAML-Arrays zusammen?
Dreftymac
10
Bedeutet dies, dass dieser Ansatz nur mit einem separaten Tool funktioniert, das sitesund zusammenführt sites+. Ich meine ein Tool, das vom Benutzer implementiert werden muss, da dies kein Standardverhalten ist yaml.
stan0
7

(Beantwortung meiner eigenen Frage, falls die von mir verwendete Lösung für jeden nützlich ist, der in Zukunft danach sucht)

Da dies keine reine YAML-Methode ist, werde ich dies als "Syntaxtransformation" implementieren, die zwischen dem YAML-Parser und dem Code liegt, der die Konfigurationsdatei tatsächlich verwendet. Meine Kernanwendung muss sich also überhaupt nicht um menschenfreundliche Redundanzvermeidungsmaßnahmen kümmern und kann direkt auf die resultierenden Strukturen einwirken.

Die Struktur, die ich verwenden werde, sieht folgendermaßen aus:

foo:
  MERGE:
    - - a
      - b
      - c
    - - 1
      - 2
      - 3

Welches würde in das Äquivalent von umgewandelt werden:

foo:
  - a
  - b
  - c
  - 1
  - 2
  - 3

Oder mit Karten:

foo:
  MERGE:
    - fork: a
      spoon: b
      knife: c
    - cup: 1
      mug: 2
      glass: 3

Würde verwandelt werden in:

foo:
  fork: a
  spoon: b
  knife: c
  cup: 1
  mug: 2
  glass: 3

Noch formeller: Nachdem ich den YAML-Parser aufgerufen habe, um native Objekte aus einer Konfigurationsdatei abzurufen, aber bevor ich die Objekte an den Rest der Anwendung übergeben habe, durchsucht meine Anwendung das Objektdiagramm nach Zuordnungen, die den einzelnen Schlüssel enthalten MERGE. Der zugeordnete Wert MERGEmuss entweder eine Liste von Listen oder eine Liste von Karten sein. Jede andere Unterstruktur ist ein Fehler.

Im Fall der Listenliste MERGEwird die gesamte Karte, die sie enthält , durch die untergeordneten Listen ersetzt, die in der Reihenfolge miteinander verknüpft sind, in der sie angezeigt wurden.

Im Fall der Kartenliste MERGEwird die gesamte Karte mit einer einzigen Karte ersetzt, die alle Schlüssel / Wert-Paare in den untergeordneten Karten enthält. Bei Überlappungen der Schlüssel wird der zuletzt in der MERGEListe vorkommende Wert aus der untergeordneten Zuordnung verwendet.

Die oben angegebenen Beispiele sind nicht so nützlich, da Sie die gewünschte Struktur direkt hätten schreiben können. Es erscheint eher als:

foo:
  MERGE:
    - *salt
    - *pepper

So können Sie eine Liste oder Karte erstellen, die alles in Knoten enthält saltund an pepperanderer Stelle verwendet wird.

(Ich gebe immer wieder diese foo:äußere Karte, um zu zeigen, dass MERGEdies der einzige Schlüssel in der Zuordnung sein muss, was bedeutet, dass MERGEsie nicht als Name der obersten Ebene angezeigt werden kann, es sei denn, es gibt keine anderen Namen der obersten Ebene.)

Ben
quelle
6

Um etwas aus den beiden Antworten hier zu verdeutlichen, wird dies nicht direkt in YAML für Listen unterstützt (es wird jedoch für Wörterbücher unterstützt, siehe Kittemons Antwort).

asmeurer
quelle
Hinweis: Dieses Problem kann auch bei der Standardverwendung von Ankern und Aliasen in YAML behoben werden. Siehe auch: Wie füge ich YAML-Arrays zusammen?
Dreftymac
5

Beachten Sie, dass Sie Zuordnungen mit Nullwerten mithilfe der alternativen Syntax erstellen können, um die Antwort von Kittemon zu ändern

foo:
    << : myanchor
    bar:
    baz:

anstelle der vorgeschlagenen Syntax

foo:
    << : myanchor
    ? bar
    ? baz

Wie bei Kittemons Vorschlag können Sie auf diese Weise Verweise auf Anker innerhalb des Mappings verwenden und das Sequenzproblem vermeiden. Ich musste dies tun, nachdem ich festgestellt hatte, dass die Symfony Yaml-Komponente v2.4.4 die ? barSyntax nicht neu organisiert .

Rindfleisch_Boolescher Wert
quelle
Wie sieht es myanchoraus?
ssc