Esiste la sintassi YAML per condividere parte di un elenco o di una mappa?


94

Quindi, so che posso fare qualcosa del genere:

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

anotherlist: *sites

E hanno siteliste anotherlistcontengono www.foo.come www.bar.com. Tuttavia, quello che voglio veramente è anotherlistche contenga anchewww.baz.com , senza dover ripetere www.foo.come www.baz.com.

In questo modo viene visualizzato un errore di sintassi nel parser YAML:

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

anotherlist: *sites
  - www.baz.com

Usando semplicemente ancoraggi e alias non sembra possibile fare quello che voglio senza aggiungere un altro livello di sottostruttura, come ad esempio:

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

anotherlist:
  - *sites
  - www.baz.com

Il che significa che il consumatore di questo file YAML deve esserne consapevole.

Esiste un modo puro YAML di fare qualcosa del genere? O dovrò utilizzare un'elaborazione post-YAML, come l'implementazione della sostituzione di variabili o il sollevamento automatico di alcuni tipi di sottostruttura? Sto già eseguendo quel tipo di post-elaborazione per gestire un paio di altri casi d'uso, quindi non sono del tutto contrario. Ma i miei file YAML saranno scritti da esseri umani, non generati dalla macchina, quindi vorrei ridurre al minimo il numero di regole che devono essere memorizzate dai miei utenti in aggiunta alla sintassi YAML standard.

Mi piacerebbe anche poter fare la cosa analoga con le mappe:

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

moresites: *sites
  Baz: www.baz.com

Ho fatto una ricerca attraverso le specifiche YAML e non sono riuscito a trovare nulla, quindi sospetto che la risposta sia semplicemente "no, non puoi farlo". Ma se qualcuno avesse qualche idea sarebbe fantastico.


EDIT: Dal momento che non ci sono state risposte, presumo che nessuno abbia notato nulla che io non abbia nella specifica YAML e che questo non possa essere fatto al livello YAML. Quindi sto aprendo la domanda all'idea per la post-elaborazione dello YAML per aiutare con questo, nel caso in cui qualcuno trovi questa domanda in futuro.


Nota: questo problema può essere risolto anche con l'uso standard di ancoraggi e alias in YAML. Vedi anche: Come unire gli array YAML?
dreftymac

Risposte:


53

Il tipo di chiave di unione è probabilmente quello che vuoi. Utilizza una <<chiave di mappatura speciale per indicare le fusioni, consentendo a un alias di una mappatura (o una sequenza di tali alias) di essere utilizzato come inizializzatore per fondersi in una singola mappatura. Inoltre, puoi ancora sovrascrivere esplicitamente i valori o aggiungerne altri che non erano presenti nell'elenco di unione.

È importante notare che funziona con le mappature, non con le sequenze come primo esempio. Questo ha senso se ci pensi e il tuo esempio sembra che probabilmente non ha bisogno di essere sequenziale comunque. La semplice modifica dei valori della sequenza in chiavi di mappatura dovrebbe fare il trucco, come nel seguente esempio (non testato):

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

Alcune cose da notare. In primo luogo, poiché <<è una chiave, può essere specificata solo una volta per nodo. In secondo luogo, quando si utilizza una sequenza come valore, l'ordine è significativo. Questo non ha importanza nell'esempio qui, poiché non ci sono valori associati, ma vale la pena essere consapevoli.


Ah, grazie! È molto utile. È un peccato che non funzioni per le sequenze, però. Hai ragione che l'ordine non è importante per questo esempio; quello che ho è concettualmente un set, ma è molto più vicino a una sequenza che a una mappatura. E la struttura di ciò che ottengo da questo è importante (motivo per cui non volevo aggiungere un altro livello di annidamento per unire le mie strutture), quindi avere una mappatura per la quale devo ignorare i valori (tutti nulli) non funziona davvero.
Ben

3
Non vedo nulla su di esso nelle attuali specifiche ufficiali YAML: yaml.org/spec/1.2/spec.html . Quella pagina non contiene la parola "merge", né il testo "<<", né la frase "key type". La sintassi << funziona però nel pacchetto yaml di Python. Sai dove posso trovare ulteriori informazioni su questo tipo di funzionalità extra?
Ben

1
Non è direttamente nelle specifiche, è descritto nel repository di tag. Altri schemi hanno una descrizione generale e un collegamento. Oltre alle chiavi di unione, ci sono anche insiemi e insiemi ordinati; tuttavia, YAML considera gli insiemi come un tipo di mappatura (ad esempio, l'esempio sopra potrebbe essere implementato come un insieme). La tua lingua ti consente di scambiare le chiavi con i valori nella mappatura risultante? Anche se dovessi implementarlo da solo, penso che sarebbe più pulito; almeno avresti già raggruppato tutti i dati e il tuo YAML sarebbe standard.
kittemon

I set però non sono mappature; una mappatura è un insieme di associazioni valore-chiave. Quando sono yaml.load(...)in Python, ottengo un dizionario come rappresentazione di una mappatura YAML. Sì, è facile post-processarlo in un set, ma devo sapere che è successo (e la complessità semantica durante la lettura / scrittura dei file di configurazione è molto più alta se la regola è "i set sono scritti come mappe con valori nulli" ). Dato che ho bisogno di una post-elaborazione tra yaml.load(...)e l'utilizzo dei dati risultanti, sia che io usi <<o MERGE, probabilmente continuerò con MERGE(che ho già implementato ora).
Ben

2
Sì, ho scoperto che !!setfunziona. Tuttavia, boilerplate troppo oscuro. Questi file sono fatti per essere leggibili / scrivibili da persone che non sono necessariamente esperti di YAML. Le persone scriveranno i loro elenchi di siti come elenchi YAML, quindi vorranno unirli e dovranno convertire il tutto in un set E ricordarsi di taggarlo esplicitamente come un set ... Ho un paio di altri post standardizzati- elaborare le cose insieme MERGEcomunque. Grazie per il tuo aiuto però!
Ben

16

Come hanno sottolineato le risposte precedenti, non esiste un supporto integrato per l'estensione delle liste in YAML. Sto offrendo un altro modo per implementarlo da soli. Considera questo:

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

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

Questo verrà elaborato in:

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

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

L'idea è di unire il contenuto di una chiave che termina con un "+" alla chiave corrispondente senza un "+". L'ho implementato in Python e pubblicato qui .

Godere!


2
Nota: questo problema può essere risolto anche con l'uso standard di ancoraggi e alias in YAML. Vedi anche: Come unire gli array YAML?
dreftymac

11
Ciò significa che questo approccio funziona solo con uno strumento separato che unisce sitese sites+. Intendo uno strumento che deve essere implementato dall'utente in quanto questo non è un yamlcomportamento predefinito ?
stan0

7

(Rispondendo alla mia domanda nel caso in cui la soluzione che sto utilizzando sia utile per chiunque la cerchi in futuro)

Senza un metodo YAML puro per farlo, lo implementerò come una "trasformazione della sintassi" che si trova tra il parser YAML e il codice che utilizza effettivamente il file di configurazione. Quindi la mia applicazione principale non deve preoccuparsi affatto di misure per evitare la ridondanza a misura d'uomo e può semplicemente agire direttamente sulle strutture risultanti.

La struttura che userò è simile a questa:

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

Che verrebbe trasformato nell'equivalente di:

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

Oppure, con le mappe:

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

Si trasformerebbe in:

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

Più formalmente, dopo aver chiamato il parser YAML per ottenere oggetti nativi da un file di configurazione, ma prima di passare gli oggetti al resto dell'applicazione, la mia applicazione percorrerà l'oggetto grafico alla ricerca di mappature contenenti la singola chiave MERGE. Il valore associato a MERGEdeve essere un elenco di elenchi o un elenco di mappe; qualsiasi altra sottostruttura è un errore.

Nel caso delle liste di liste, l'intera mappa contenente MERGEsarà sostituita dalle liste figlie concatenate insieme nell'ordine in cui sono apparse.

Nel caso dell'elenco delle mappe, l'intera mappa contenente MERGE sarà sostituita da una singola mappa contenente tutte le coppie chiave / valore nelle mappe figlie. In caso di sovrapposizione delle chiavi, MERGEverrà utilizzato il valore della mappa figlia che si verifica per ultima nell'elenco.

Gli esempi forniti sopra non sono così utili, poiché avresti potuto semplicemente scrivere la struttura che volevi direttamente. È più probabile che appaia come:

foo:
  MERGE:
    - *salt
    - *pepper

Permettendoti di creare un elenco o una mappa contenente tutto nei nodi salt e pepperutilizzato altrove.

(Continuo a dare quella foo:mappa esterna per mostrare che MERGEdeve essere l' unica chiave nella sua mappatura, il che significa che MERGEnon può apparire come un nome di primo livello a meno che non ci siano altri nomi di primo livello)


6

Per chiarire qualcosa dalle due risposte qui, questo non è supportato direttamente in YAML per gli elenchi (ma è supportato per i dizionari, vedi la risposta di kittemon).


Nota: questo problema può essere risolto anche con l'uso standard di ancoraggi e alias in YAML. Vedi anche: Come unire gli array YAML?
dreftymac

5

Per ignorare la risposta di Kittemon, nota che puoi creare mappature con valori nulli usando la sintassi alternativa

foo:
    << : myanchor
    bar:
    baz:

invece della sintassi suggerita

foo:
    << : myanchor
    ? bar
    ? baz

Come il suggerimento di Kittemon, questo ti permetterà di usare riferimenti ad ancoraggi all'interno della mappatura ed evitare il problema della sequenza. Mi sono ritrovato a doverlo fare dopo aver scoperto che il componente Symfony Yaml v2.4.4 non ricorre alla ? barsintassi.


che myanchoraspetto ha?
ssc
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.