132 Stimmen

Gibt es eine YAML-Syntax für die Freigabe von Teilen einer Liste oder Karte?

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

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

anotherlist: *sites

Und haben sitelist y anotherlist beide enthalten www.foo.com y www.bar.com . Was ich jedoch wirklich möchte, ist, dass anotherlist a auch enthalten www.baz.com ohne wiederholen zu müssen www.foo.com y www.baz.com .

Dies führt zu einem Syntaxfehler im YAML-Parser:

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

anotherlist: *sites
  - www.baz.com

Nur mit Ankern und Aliasen 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

Das bedeutet, dass der Konsument dieser YAML-Datei davon Kenntnis haben muss.

Gibt es eine reine YAML-Methode, um so etwas zu tun? Oder muss ich eine Post-YAML-Verarbeitung verwenden, wie z.B. die Implementierung von Variablensubstitution oder die automatische Aufhebung bestimmter Arten von Unterstrukturen? Ich mache diese Art von Nachbearbeitung bereits für einige andere Anwendungsfälle, daher bin ich dem nicht ganz abgeneigt. Da meine YAML-Dateien aber von Menschen geschrieben und nicht maschinell generiert werden sollen, möchte ich die Anzahl der Regeln, die sich meine Benutzer zusätzlich zur YAML-Standardsyntax merken müssen, möglichst gering halten.

Das Gleiche würde ich auch gerne mit Karten machen können:

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

moresites: *sites
  Baz: www.baz.com

Ich habe eine Suche durch die YAML-Spezifikation und konnte nichts finden, so dass ich vermute, die Antwort lautet einfach "Nein, das geht nicht". Aber wenn jemand irgendwelche Ideen hat, wäre das großartig.


EDITAR: Da es keine Antworten gab, gehe ich davon aus, dass niemand etwas entdeckt hat, was ich in der YAML-Spezifikation nicht gefunden habe und dass dies nicht auf der YAML-Ebene möglich ist. Ich eröffne daher die Frage nach Ideen für eine Nachbearbeitung der YAML, um dies zu unterstützen, falls jemand diese Frage in Zukunft findet.

69voto

kittemon Punkte 882

Der Typ des Zusammenführungsschlüssels ist wahrscheinlich das, was Sie wollen. Es verwendet eine spezielle << Mapping-Schlüssel, um Zusammenführungen anzuzeigen, so dass ein Alias zu einem Mapping (oder eine Folge solcher Aliase) als Initialisierer für die Zusammenführung zu einem einzigen Mapping verwendet werden kann. Außerdem können Sie immer noch explizit Werte überschreiben oder weitere hinzufügen, die in der Zusammenführungsliste nicht vorhanden waren.

Es ist wichtig zu beachten, dass es mit Mappings funktioniert, nicht mit Sequenzen wie in Ihrem ersten Beispiel. Das macht Sinn, wenn man darüber nachdenkt, und Ihr Beispiel sieht so aus, als ob es wahrscheinlich sowieso nicht sequentiell sein muss. Ändern Sie einfach Ihre Sequenzwerte in Zuordnungsschlüssel, 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 sind zu beachten. Erstens, da << ein Schlüssel ist, kann er nur einmal pro Knoten angegeben werden. Zweitens ist bei der Verwendung einer Sequenz als Wert die Reihenfolge von Bedeutung. Dies spielt in diesem Beispiel keine Rolle, da es keine zugehörigen Werte gibt, aber es ist wichtig, sich dessen bewusst zu sein.

20voto

Alexander Ryzhov Punkte 2314

Wie in den vorangegangenen Antworten bereits erwähnt, gibt es in YAML keine eingebaute Unterstützung für die Erweiterung von Listen. Ich biete Ihnen hier eine weitere Möglichkeit an, dies selbst zu implementieren. Betrachten Sie dies:

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

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

Dies wird in verarbeitet werden:

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 "+" zusammenzuführen. Ich habe dies in Python implementiert und veröffentlicht aquí .

10voto

Ben Punkte 62082

(Ich beantworte meine eigene Frage, falls die Lösung, die ich verwende, für andere nützlich ist, die in Zukunft danach suchen)

Da es keine reine YAML-Möglichkeit gibt, dies zu tun, werde ich dies als "Syntaxtransformation" zwischen dem YAML-Parser und dem Code, der die Konfigurationsdatei verwendet, implementieren. So muss sich meine Kernanwendung nicht um irgendwelche menschenfreundlichen Redundanzvermeidungsmaßnahmen kümmern, sondern kann direkt auf die resultierenden Strukturen einwirken.

Die Struktur, die ich verwenden werde, sieht wie folgt aus:

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

Das 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 umgewandelt werden in:

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

Nach dem Aufruf des YAML-Parsers zum Abrufen nativer Objekte aus einer Konfigurationsdatei, aber vor der Übergabe der Objekte an den Rest der Anwendung, sucht meine Anwendung im Objektgraphen nach Mappings, die den einzelnen Schlüssel MERGE . Der Wert, der mit MERGE muss entweder eine Liste von Listen oder eine Liste von Maps sein; jede andere Unterstruktur ist ein Fehler.

Im Fall der Liste der Listen wird die gesamte Karte mit MERGE wird durch die untergeordneten Listen ersetzt, die in der Reihenfolge ihres Erscheinens aneinandergereiht werden.

Im Fall der Liste der Karten wird die gesamte Karte, die MERGE wird durch eine einzige Map ersetzt, die alle Schlüssel/Wertpaare in den Child-Maps enthält. Wenn sich die Schlüssel überschneiden, wird der Wert aus der Child-Map, der als letzter in der MERGE Liste verwendet werden.

Die oben angeführten Beispiele sind nicht sehr nützlich, da Sie die gewünschte Struktur auch direkt hätten schreiben können. Es ist wahrscheinlicher, dass es so aussieht:

foo:
  MERGE:
    - *salt
    - *pepper

Sie können eine Liste oder eine Karte erstellen, die alles in Knoten enthält salt y pepper anderswo verwendet werden.

(Ich gebe das immer wieder foo: äußere Karte zu zeigen, dass MERGE muss die nur Schlüssel in seiner Zuordnung, was bedeutet, dass MERGE kann nur dann als Top-Level-Name erscheinen, wenn es keine anderen Top-Level-Namen gibt)

8voto

asmeurer Punkte 79555

Um etwas aus den beiden Antworten hier klarzustellen, dies wird in YAML für Listen nicht direkt unterstützt (für Dictionaries hingegen schon, siehe Antwort von kittemon).

5voto

beef_boolean Punkte 148

Um die Antwort von Kittemon zu ergänzen, beachten Sie, dass Sie Zuordnungen mit Nullwerten mit der alternativen Syntax erstellen können

foo:
    << : myanchor
    bar:
    baz:

anstelle der vorgeschlagenen Syntax

foo:
    << : myanchor
    ? bar
    ? baz

Wie Kittemon vorgeschlagen hat, können Sie auf diese Weise Verweise auf Anker innerhalb der Zuordnung verwenden und das Problem der Reihenfolge vermeiden. Ich musste dies tun, nachdem ich herausgefunden hatte, dass die Symfony Yaml Komponente v2.4.4 nicht die ? bar Syntax.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X