Bir listenin veya haritanın bir bölümünü paylaşmak için YAML sözdizimi var mı?


95

Yani, bunun gibi bir şey yapabileceğimi biliyorum:

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

anotherlist: *sites

Ve sahip sitelistve anotherlisther ikisi de www.foo.comve içerir www.bar.com. Ancak, ne gerçekten istemek içindir anotherlistiçin de içerirler www.baz.comtekrarlamak zorunda kalmadan, www.foo.comve www.baz.com.

Bunu yapmak bana YAML ayrıştırıcısında bir sözdizimi hatası veriyor:

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

anotherlist: *sites
  - www.baz.com

Sadece çapa ve takma ad kullanarak, istediğim şeyi başka bir alt yapı düzeyi eklemeden yapmak mümkün görünmüyor, örneğin:

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

anotherlist:
  - *sites
  - www.baz.com

Bu, bu YAML dosyasının tüketicisinin bundan haberdar olması gerektiği anlamına gelir.

Böyle bir şey yapmanın saf bir YAML yolu var mı? Ya da değişken ikamesi uygulamak veya belirli alt yapı türlerinin otomatik kaldırılması gibi bazı YAML sonrası işlemleri kullanmak zorunda mıyım? Zaten birkaç başka kullanım durumunu ele almak için bu tür bir son işlem yapıyorum, bu yüzden bundan tamamen hoşlanmıyorum. Ancak YAML dosyalarım makine tarafından değil, insanlar tarafından yazılacak, bu yüzden kullanıcılarım tarafından ezberlenmesi gereken kuralların sayısını standart YAML sözdizimine göre en aza indirmek istiyorum.

Ayrıca haritalarla benzer bir şey yapabilmek isterim:

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

moresites: *sites
  Baz: www.baz.com

YAML spesifikasyonunda bir arama yaptım ve hiçbir şey bulamadım, bu yüzden cevabın sadece "hayır bunu yapamazsınız" olduğundan şüpheleniyorum. Ama herhangi birinin harika olacak bir fikri varsa.


DÜZENLEME: Cevap olmadığından, YAML spesifikasyonunda hiç kimsenin sahip olmadığım bir şeyi fark etmediğini ve bunun YAML katmanında yapılamayacağını varsayıyorum. Bu yüzden soruyu, gelecekte bu soruyu herhangi birinin bulması durumunda, YAML'nin buna yardımcı olması için sonradan işleme fikrine açıyorum.


Not: Bu sorun, YAML'de Çapaların ve Takma Adların standart kullanımıyla da giderilebilir. Ayrıca bkz: YAML dizileri nasıl birleştirilir?
dreftymac

Yanıtlar:


53

Birleştirme anahtarı türü muhtemelen istediğiniz şeydir. <<Birleşmeleri belirtmek için özel bir eşleme anahtarı kullanır ve bir eşlemenin diğer adının (veya bu tür diğer adların bir dizisinin) tek bir eşlemede birleştirmek için bir başlatıcı olarak kullanılmasına izin verir. Ek olarak, değerleri açıkça geçersiz kılmaya devam edebilir veya birleştirme listesinde olmayan daha fazlasını ekleyebilirsiniz.

İlk örneğiniz olarak dizilerle değil, eşlemelerle çalıştığına dikkat etmek önemlidir. Bu, onu düşündüğünüzde mantıklı geliyor ve örneğiniz muhtemelen sıralı olması gerekmiyor gibi görünüyor. Aşağıdaki (test edilmemiş) örnekte olduğu gibi, sıra değerlerinizi eşleme anahtarlarına değiştirmeniz yeterli olacaktır:

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

Dikkat edilmesi gereken bazı şeyler. İlk olarak, <<bir anahtar olduğu için düğüm başına yalnızca bir kez belirtilebilir. İkinci olarak, değer olarak bir dizi kullanıldığında sıra önemlidir. Buradaki örnekte bunun bir önemi yoktur, çünkü ilişkili değerler yoktur, ancak farkında olmaya değer.


Ah teşekkürler! Bu oldukça yardımcı oldu. Yine de sekanslar için çalışmaması utanç verici. Haklısın, bu örnek için düzenin önemi yok; Sahip olduğum şey kavramsal olarak bir küme, ancak bu bir diziye bir eşlemeden çok daha yakın. Ve bundan çıkardığım şeyin yapısı önemlidir (bu yüzden yapılarımı birleştirmek için başka bir iç içe geçme katmanı eklemek istemedim), bu nedenle (tüm boş) değerleri görmezden gelmem gereken bir eşlemeye sahip olmak gerçekten işe yaramıyor.
Ben

3
Şu anki resmi YAML spesifikasyonunda hiçbir şey görmüyorum: yaml.org/spec/1.2/spec.html . Bu sayfa "birleştirme" kelimesini, "<<" metnini veya "anahtar türü" ifadesini içermiyor. << sözdizimi Python yaml paketinde çalışır. Bu tür ekstra özellikler hakkında nereden daha fazla bilgi edinebileceğimi biliyor musunuz?
Ben

1
Doğrudan spesifikasyonda değil, etiket deposunda açıklanıyor. Diğer Şemaların genel bir açıklaması ve bağlantısı vardır. Birleştirme anahtarlarının yanı sıra, kümeler ve sıralı kümeler de vardır; ancak YAML, kümeleri bir eşleme türü olarak kabul eder (örneğin, yukarıdaki örnek bir küme olarak uygulanabilir). Diliniz, ortaya çıkan eşlemede değerlerle anahtarları değiştirmenize izin veriyor mu? Bunu kendiniz uygulamanız gerekse bile, daha temiz olacağını düşünüyorum; en azından tüm verileri zaten bir arada gruplandırmış olursunuz ve YAML'niz standart olur.
kittemon

Kümeler eşleme değildir; bir eşleme, bir dizi anahtar-değer ilişkisidir. Ben ne zaman yaml.load(...)Python, bir YAML eşleme temsili olarak bir sözlük olsun. Evet, bunu bir küme halinde sonradan işlemek kolaydır, ancak bunun olduğunu bilmeliyim (ve yapılandırma dosyalarını okurken / yazarken anlamsal karmaşıklık, kural "kümeler boş değerlerle haritalar olarak yazılırsa" çok daha yüksektir. ). yaml.load(...)İster kullansam <<da MERGE, ister kullansam da , sonuçta elde edilen veriler arasında bir son işlemeye ihtiyacım olduğu için , muhtemelen bağlı kalacağım MERGE(şimdi zaten uyguladığım).
Ben

2
Evet, !!setişe yaradığını buldum . Yine de çok fazla anlaşılmaz standart metin. Bu dosyalar, YAML uzmanı olması gerekmeyen kişiler tarafından okunabilir / yazılabilir hale getirilmiştir. İnsanlar site listelerini YAML listeleri olarak yazacaklar, sonra onları birleştirmek isteyecek ve her şeyi bir sete dönüştürmek zorunda kalacak VE bunu açıkça bir set olarak etiketlemeyi unutmayacaksınız ... MERGEyine de bir şeyler işlemek . Yine de yardımınız için teşekkürler!
Ben

17

Önceki yanıtların işaret ettiği gibi, YAML'de listeleri genişletmek için yerleşik bir destek yoktur. Kendiniz uygulamak için başka bir yol daha öneriyorum. Bunu düşün:

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

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

Bu şu şekilde işlenecek:

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

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

Buradaki fikir, '+' ile biten bir anahtarın içeriğini '+' içermeyen karşılık gelen anahtarla birleştirmektir. Bunu Python'da uyguladım ve burada yayınladım .

Zevk almak!


2
Not: Bu sorun, YAML'de Çapaların ve Takma Adların standart kullanımıyla da giderilebilir. Ayrıca bkz: YAML dizileri nasıl birleştirilir?
dreftymac

12
Bu, bu yaklaşımın yalnızca birleşen ayrı bir araçla çalıştığı sitesve sites+. Bu varsayılan bir yamldavranış olmadığı için kullanıcı tarafından uygulanması gereken bir aracı kastediyorum.
stan0

7

(Kullandığım çözümün gelecekte bunu arayan herkes için yararlı olması durumunda kendi sorumu yanıtlamak)

Bunu yapmanın saf YAML yolu olmadan, bunu YAML ayrıştırıcısı ile yapılandırma dosyasını kullanan kod arasında oturan bir "sözdizimi dönüşümü" olarak uygulayacağım. Dolayısıyla, temel uygulamamın herhangi bir insan dostu fazlalıktan kaçınma önlemi konusunda endişelenmesine gerek yok ve doğrudan sonuçta ortaya çıkan yapılar üzerinde hareket edebilir.

Kullanacağım yapı şuna benzer:

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

Aşağıdakinin eşdeğerine dönüştürülecek:

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

Veya haritalarla:

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

Şuna dönüştürülür:

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

Daha resmi olarak, bir yapılandırma dosyasından yerel nesneleri almak için YAML ayrıştırıcısını çağırdıktan sonra, ancak nesneleri uygulamanın geri kalanına iletmeden önce, uygulamam, tek anahtarı içeren eşlemeleri bulmak için nesne grafiğini gezer MERGE. İle ilişkili değer MERGEya bir liste listesi ya da bir harita listesi olmalıdır; diğer herhangi bir altyapı bir hatadır.

Listeler listesi durumunda, içeren haritanın tamamı, MERGEgöründükleri sıraya göre birleştirilmiş alt listelerle değiştirilecektir.

Harita listesi durumunda, içeren haritanın tamamı MERGE, alt haritalardaki tüm anahtar / değer çiftlerini içeren tek bir harita ile değiştirilecektir. Anahtarlarda üst üste binme olduğunda, MERGElistede en son meydana gelen alt haritadaki değer kullanılacaktır.

Yukarıda verilen örnekler, istediğiniz yapıyı doğrudan yazabileceğiniz için o kadar da kullanışlı değildir. Şu şekilde görünme olasılığı daha yüksektir:

foo:
  MERGE:
    - *salt
    - *pepper

Düğümlerdeki her şeyi içeren saltve pepperbaşka yerlerde kullanılan bir liste veya harita oluşturmanıza izin verir .

(Eşlemesinde tek anahtar olması gerektiğini foo:göstermek için dış haritayı vermeye devam ediyorum , bu da başka üst düzey adlar yoksa üst düzey ad olarak görünemeyeceği anlamına gelir )MERGEMERGE


6

Buradaki iki yanıttan bir şeyi açıklığa kavuşturmak için, bu, listeler için doğrudan YAML'de desteklenmez (ancak sözlükler için desteklenir, kittemon'un cevabına bakın).


Not: Bu sorun, YAML'de Çapaların ve Takma Adların standart kullanımıyla da giderilebilir. Ayrıca bkz: YAML dizileri nasıl birleştirilir?
dreftymac

5

Kittemon'un cevabından kurtulmak için, alternatif sözdizimini kullanarak boş değerlerle eşlemeler oluşturabileceğinizi unutmayın.

foo:
    << : myanchor
    bar:
    baz:

önerilen sözdizimi yerine

foo:
    << : myanchor
    ? bar
    ? baz

Kittemon'un önerisi gibi, bu da haritalama içindeki çapalara referansları kullanmanıza ve sıra sorununu önlemenize izin verecektir. Symfony Yaml bileşeni v2.4.4'ün ? barsözdizimini kaydetmediğini keşfettikten sonra bunu yapmam gerektiğini anladım .


neye myanchorbenziyor
ssc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.