Ini tidak akan berhasil:
penggabungan hanya didukung oleh spesifikasi YAML untuk pemetaan dan bukan untuk urutan
Anda benar-benar mencampur hal-hal dengan memiliki kunci gabungan <<
diikuti oleh pemisah kunci / nilai :
dan nilai yang merupakan referensi dan kemudian melanjutkan dengan daftar di tingkat indentasi yang sama
Ini bukan YAML yang benar:
combine_stuff:
x: 1
- a
- b
Jadi contoh sintaks Anda bahkan tidak akan masuk akal sebagai proposal ekstensi YAML.
Jika Anda ingin melakukan sesuatu seperti menggabungkan beberapa array, Anda mungkin ingin mempertimbangkan sintaks seperti:
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
di mana s1
, s2
, s3
adalah jangkar pada urutan (tidak ditampilkan) bahwa Anda ingin menggabungkan menjadi urutan baru dan kemudian memiliki d
, e
dan f
ditambahkan ke itu. Namun YAML menyelesaikan jenis kedalaman struktur ini terlebih dahulu, jadi tidak ada konteks nyata yang tersedia selama pemrosesan kunci penggabungan. Tidak ada larik / daftar yang tersedia untuk Anda di mana Anda dapat melampirkan nilai yang diproses (urutan berlabuh) ke.
Anda dapat mengambil pendekatan seperti yang diusulkan oleh @dreftymac, tetapi ini memiliki kerugian besar bahwa Anda perlu mengetahui urutan bersarang mana yang harus diratakan (yaitu dengan mengetahui "jalur" dari akar struktur data yang dimuat ke urutan induk), atau bahwa Anda secara rekursif menjalankan struktur data yang dimuat untuk mencari larik / daftar bersarang dan meratakan semuanya tanpa pandang bulu.
Solusi yang lebih baik IMO adalah menggunakan tag untuk memuat struktur data yang melakukan perataan untuk Anda. Hal ini memungkinkan untuk dengan jelas menunjukkan apa yang perlu diratakan dan apa yang tidak dan memberi Anda kendali penuh atas apakah perataan ini dilakukan selama pemuatan, atau dilakukan selama akses. Yang mana yang harus dipilih adalah soal kemudahan implementasi dan efisiensi waktu dan ruang penyimpanan. Ini adalah trade-off yang sama yang perlu dilakukan untuk menerapkan fitur kunci gabungan dan tidak ada solusi tunggal yang selalu terbaik.
Misalnya ruamel.yaml
perpustakaan saya menggunakan brute force merge-dicts selama pemuatan saat menggunakan safe-loader, yang menghasilkan kamus gabungan yang merupakan dicts Python normal. Penggabungan ini harus dilakukan di muka, dan data duplikat (ruang tidak efisien) tetapi cepat dalam pencarian nilai. Saat menggunakan round-trip-loader, Anda ingin dapat membuang penggabungan yang tidak digabungkan, sehingga harus tetap dipisahkan. Diktekan seperti struktur data yang dimuat sebagai hasil dari pemuatan bolak-balik, hemat ruang tetapi aksesnya lebih lambat, karena perlu mencoba dan mencari kunci yang tidak ditemukan dalam dikt itu sendiri dalam penggabungan (dan ini tidak di-cache, jadi itu perlu dilakukan setiap saat). Tentu saja pertimbangan seperti itu tidak terlalu penting untuk file konfigurasi yang relatif kecil.
Berikut ini mengimplementasikan skema seperti penggabungan untuk daftar di python menggunakan objek dengan tag flatten
yang dengan cepat muncul kembali menjadi item yang daftar dan diberi tag toflatten
. Dengan menggunakan dua tag ini, Anda dapat memiliki file YAML:
l1: &x1 !toflatten
- 1
- 2
l2: &x2
- 3
- 4
m1: !flatten
- *x1
- *x2
- [5, 6]
- !toflatten [7, 8]
(penggunaan urutan aliran vs gaya blok benar-benar sewenang-wenang dan tidak memiliki pengaruh pada hasil yang dimuat).
Saat mengulangi item yang merupakan nilai untuk kunci m1
ini "berulang" ke dalam urutan yang diberi tag toflatten
, tetapi menampilkan daftar lain (alias atau tidak) sebagai satu item.
Salah satu cara yang mungkin dengan kode Python untuk mencapainya adalah:
import sys
from pathlib import Path
import ruamel.yaml
yaml = ruamel.yaml.YAML()
@yaml.register_class
class Flatten(list):
yaml_tag = u'!flatten'
def __init__(self, *args):
self.items = args
@classmethod
def from_yaml(cls, constructor, node):
x = cls(*constructor.construct_sequence(node, deep=True))
return x
def __iter__(self):
for item in self.items:
if isinstance(item, ToFlatten):
for nested_item in item:
yield nested_item
else:
yield item
@yaml.register_class
class ToFlatten(list):
yaml_tag = u'!toflatten'
@classmethod
def from_yaml(cls, constructor, node):
x = cls(constructor.construct_sequence(node, deep=True))
return x
data = yaml.load(Path('input.yaml'))
for item in data['m1']:
print(item)
keluaran yang mana:
1
2
[3, 4]
[5, 6]
7
8
Seperti yang Anda lihat, Anda dapat melihat, dalam urutan yang perlu diratakan, Anda dapat menggunakan alias ke urutan yang diberi tag atau Anda dapat menggunakan urutan yang diberi tag. YAML tidak mengizinkan Anda melakukan:
- !flatten *x2
, yaitu menandai urutan berlabuh, karena ini pada dasarnya akan membuatnya menjadi struktur data yang berbeda.
Menggunakan tag eksplisit IMO lebih baik daripada melakukan keajaiban seperti pada kunci gabungan YAML <<
. Jika tidak ada lagi Anda sekarang harus melalui rintangan jika Anda kebetulan memiliki file YAML dengan pemetaan yang memiliki kunci
<<
yang Anda tidak ingin bertindak seperti kunci gabungan, misalnya ketika Anda membuat pemetaan operator C ke deskripsinya dalam bahasa Inggris (atau bahasa alami lainnya).