Apakah ada sintaks YAML untuk berbagi bagian dari daftar atau peta?

95

Jadi, saya tahu saya bisa melakukan sesuatu seperti ini:

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

anotherlist: *sites

Dan memiliki sitelistdan anotherlistkeduanya mengandung www.foo.comdan www.bar.com. Namun, apa yang saya inginkan adalah untuk anotherlistuntuk juga mengandung www.baz.com, tanpa harus mengulang www.foo.comdan www.baz.com.

Melakukan ini memberi saya kesalahan sintaks di parser YAML:

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

anotherlist: *sites
  - www.baz.com

Hanya dengan menggunakan jangkar dan alias, sepertinya tidak mungkin melakukan apa yang saya inginkan tanpa menambahkan level substruktur lain, seperti:

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

anotherlist:
  - *sites
  - www.baz.com

Artinya, pengguna file YAML ini harus menyadarinya.

Apakah ada cara YAML murni untuk melakukan sesuatu seperti ini? Atau apakah saya harus menggunakan beberapa pemrosesan pasca-YAML, seperti menerapkan substitusi variabel atau pengangkatan otomatis jenis substruktur tertentu? Saya sudah melakukan pasca-pemrosesan semacam itu untuk menangani beberapa kasus penggunaan lainnya, jadi saya tidak sepenuhnya menolaknya. Tetapi file YAML saya akan ditulis oleh manusia, bukan yang dibuat oleh mesin, jadi saya ingin meminimalkan jumlah aturan yang perlu dihafal oleh pengguna saya di atas sintaks YAML standar.

Saya juga ingin dapat melakukan hal serupa dengan peta:

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

moresites: *sites
  Baz: www.baz.com

Saya telah mencari melalui spesifikasi YAML , dan tidak dapat menemukan apa pun, jadi saya curiga jawabannya adalah "tidak, Anda tidak dapat melakukan ini". Tapi jika ada yang punya ide, itu bagus.


EDIT: Karena tidak ada jawaban, saya berasumsi bahwa tidak ada yang melihat apa pun yang belum saya lihat di spesifikasi YAML dan ini tidak dapat dilakukan di lapisan YAML. Jadi saya membuka pertanyaan untuk ide pasca-pemrosesan YAML untuk membantu hal ini, jika ada yang menemukan pertanyaan ini di masa mendatang.

Ben
sumber
Catatan: Masalah ini juga dapat diatasi dengan penggunaan standar Jangkar dan Alias ​​di YAML. Lihat juga: Bagaimana cara menggabungkan array YAML?
dreftymac

Jawaban:

53

Jenis kunci gabungan mungkin yang Anda inginkan. Ini menggunakan <<kunci pemetaan khusus untuk menunjukkan penggabungan, memungkinkan alias ke pemetaan (atau urutan alias tersebut) untuk digunakan sebagai penginisialisasi untuk bergabung menjadi satu pemetaan. Selain itu, Anda masih dapat mengganti nilai secara eksplisit, atau menambahkan lebih banyak nilai yang tidak ada di daftar gabungan.

Penting untuk dicatat bahwa ini berfungsi dengan pemetaan, bukan urutan sebagai contoh pertama Anda. Ini masuk akal ketika Anda memikirkannya, dan contoh Anda sepertinya tidak perlu berurutan. Cukup mengubah nilai urutan Anda ke kunci pemetaan sudah cukup, seperti pada contoh berikut (belum teruji):

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

Beberapa hal yang perlu diperhatikan. Pertama, karena <<merupakan kunci, itu hanya dapat ditentukan sekali per node. Kedua, saat menggunakan urutan sebagai nilainya, urutannya signifikan. Ini tidak masalah dalam contoh di sini, karena tidak ada nilai yang terkait, tetapi perlu diperhatikan.

kittemon
sumber
Terima kasih! Itu sangat membantu. Sayang sekali itu tidak berfungsi untuk urutan. Anda benar bahwa urutan tidak penting untuk contoh ini; apa yang saya miliki secara konseptual adalah satu set, tapi itu memetakan jauh lebih dekat ke urutan daripada ke pemetaan. Dan struktur dari apa yang saya dapatkan dari ini penting (itulah sebabnya saya tidak ingin hanya menambahkan lapisan bersarang lain untuk menggabungkan struktur saya), jadi memiliki pemetaan yang perlu saya abaikan nilai (semua nol) tidak tidak benar-benar berfungsi.
Ben
3
Saya tidak melihat apa pun di dalamnya dalam spesifikasi YAML resmi saat ini: yaml.org/spec/1.2/spec.html . Halaman itu tidak mengandung kata "merge", atau teks "<<", atau frase "key type". Sintaks << bekerja dalam paket Python yaml. Tahukah Anda di mana saya dapat mengetahui lebih banyak tentang fitur tambahan semacam ini?
Ben
1
Ini tidak langsung ada dalam spesifikasi, itu dijelaskan dalam repositori tag. Skema lain memiliki gambaran umum dan tautan. Selain kunci gabungan, ada juga set dan set terurut; namun, YAML menganggap himpunan sebagai jenis pemetaan (mis., contoh di atas dapat diimplementasikan sebagai himpunan). Apakah bahasa Anda memungkinkan Anda untuk menukar kunci dengan nilai dalam pemetaan yang dihasilkan? Bahkan jika Anda harus menerapkannya sendiri, saya pikir itu akan lebih bersih; Anda setidaknya sudah memiliki semua data yang sudah dikelompokkan bersama, dan YAML Anda menjadi standar.
kittemon
Set bukanlah pemetaan; pemetaan adalah sekumpulan asosiasi nilai kunci. Saat saya yaml.load(...)menggunakan Python, saya mendapatkan kamus sebagai representasi dari pemetaan YAML. Ya, mudah untuk memposting prosesnya menjadi satu set, tetapi saya harus tahu bahwa itu terjadi (dan kerumitan semantik saat membaca / menulis file konfigurasi jauh lebih tinggi jika aturannya adalah "set ditulis sebagai peta dengan nilai null" ). Mengingat bahwa saya memerlukan pemrosesan pasca antara yaml.load(...)dan menggunakan data yang dihasilkan apakah saya menggunakan <<atau MERGE, saya mungkin akan tetap menggunakannya MERGE(yang telah saya terapkan sekarang).
Ben
2
Ya, menurutku itu !!setberhasil. Terlalu banyak boilerplate yang tidak jelas. File-file ini dibuat agar dapat dibaca / ditulisi manusia, oleh orang-orang yang belum tentu ahli YAML. Orang-orang akan menuliskan daftar situs mereka sebagai daftar YAML, kemudian ingin menggabungkannya dan harus mengubah semuanya menjadi satu set DAN ingat untuk secara eksplisit menandainya sebagai satu set ... Saya punya beberapa pos standar lainnya- memproses hal-hal bersama MERGE. Terima kasih atas bantuan Anda!
Ben
17

Seperti yang ditunjukkan oleh jawaban sebelumnya, tidak ada dukungan bawaan untuk memperluas daftar di YAML. Saya menawarkan cara lain untuk menerapkannya sendiri. Pertimbangkan ini:

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

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

Ini akan diolah menjadi:

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

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

Idenya adalah untuk menggabungkan konten kunci yang diakhiri dengan '+' ke kunci yang sesuai tanpa '+'. Saya menerapkan ini dengan Python dan menerbitkannya di sini .

Nikmati!

Alexander Ryzhov
sumber
2
Catatan: Masalah ini juga dapat diatasi dengan penggunaan standar Jangkar dan Alias ​​di YAML. Lihat juga: Bagaimana cara menggabungkan array YAML?
dreftymac
12
Apakah ini berarti pendekatan ini hanya berfungsi dengan alat terpisah yang menggabungkan sitesdan sites+. Maksud saya alat yang harus diterapkan oleh pengguna karena ini bukan yamlperilaku default ?
stan0
7

(Menjawab pertanyaan saya sendiri jika solusi yang saya gunakan berguna bagi siapa saja yang mencari ini di masa mendatang)

Tanpa cara murni-YAML untuk melakukan ini, saya akan menerapkan ini sebagai "transformasi sintaks" yang berada di antara pengurai YAML dan kode yang benar-benar menggunakan file konfigurasi. Jadi aplikasi inti saya tidak perlu khawatir sama sekali tentang tindakan penghindaran redundansi yang ramah manusia, dan hanya dapat bertindak langsung pada struktur yang dihasilkan.

Struktur yang akan saya gunakan terlihat seperti ini:

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

Yang akan diubah menjadi setara dengan:

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

Atau, dengan peta:

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

Akan diubah menjadi:

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

Secara lebih formal, setelah memanggil pengurai YAML untuk mendapatkan objek asli dari file konfigurasi, tetapi sebelum meneruskan objek ke aplikasi lainnya, aplikasi saya akan menjalankan grafik objek mencari pemetaan yang berisi kunci tunggal MERGE. Nilai yang terkait dengan MERGEharus berupa daftar daftar, atau daftar peta; substruktur lainnya adalah kesalahan.

Dalam kasus daftar daftar, seluruh peta yang berisi MERGEakan diganti dengan daftar turunan yang digabungkan bersama dalam urutan kemunculannya.

Dalam kasus daftar peta, seluruh peta yang berisi MERGEakan diganti dengan satu peta yang berisi semua pasangan kunci / nilai di peta anak. Jika ada tumpang tindih dalam kunci, nilai dari peta anak yang terjadi terakhir dalam MERGEdaftar akan digunakan.

Contoh-contoh yang diberikan di atas tidak begitu berguna, karena Anda bisa saja menulis struktur yang Anda inginkan secara langsung. Ini lebih mungkin muncul sebagai:

foo:
  MERGE:
    - *salt
    - *pepper

Memungkinkan Anda membuat daftar atau peta yang berisi semua yang ada di node saltdan pepperdigunakan di tempat lain.

(Saya terus memberikan foo:peta luar itu untuk menunjukkan bahwa MERGEharus menjadi satu - satunya kunci dalam pemetaannya, yang berarti itu MERGEtidak dapat muncul sebagai nama tingkat atas kecuali tidak ada nama tingkat atas lainnya)

Ben
sumber
6

Untuk memperjelas sesuatu dari dua jawaban di sini, ini tidak didukung secara langsung di YAML untuk daftar (tetapi didukung untuk kamus, lihat jawaban kittemon).

asmeurer
sumber
Catatan: Masalah ini juga dapat diatasi dengan penggunaan standar Jangkar dan Alias ​​di YAML. Lihat juga: Bagaimana cara menggabungkan array YAML?
dreftymac
5

Untuk mendukung jawaban Kittemon, perhatikan bahwa Anda dapat membuat pemetaan dengan nilai null menggunakan sintaks alternatif.

foo:
    << : myanchor
    bar:
    baz:

alih-alih sintaks yang disarankan

foo:
    << : myanchor
    ? bar
    ? baz

Seperti saran Kittemon, ini akan memungkinkan Anda untuk menggunakan referensi ke jangkar di dalam pemetaan dan menghindari masalah urutan. Saya mendapati diri saya perlu melakukan ini setelah menemukan bahwa komponen Symfony Yaml v2.4.4 tidak mengubah ? barsintaks.

beef_boolean
sumber
myanchorterlihat seperti apa
ssc