มีไวยากรณ์ YAML สำหรับการแบ่งปันบางส่วนของรายการหรือแผนที่หรือไม่?


95

ดังนั้นฉันรู้ว่าฉันสามารถทำสิ่งนี้ได้:

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

anotherlist: *sites

และมีsitelistและanotherlistทั้งสองมีwww.foo.comและwww.bar.com. แต่สิ่งที่ผมต้องการคือanotherlistการยังมีwww.baz.comโดยไม่ต้องทำซ้ำและwww.foo.comwww.baz.com

การทำเช่นนี้ทำให้ฉันมีข้อผิดพลาดทางไวยากรณ์ในตัวแยกวิเคราะห์ YAML:

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

anotherlist: *sites
  - www.baz.com

เพียงแค่ใช้จุดยึดและนามแฝงดูเหมือนจะไม่สามารถทำสิ่งที่ฉันต้องการได้โดยไม่ต้องเพิ่มโครงสร้างย่อยอีกระดับเช่น:

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

anotherlist:
  - *sites
  - www.baz.com

ซึ่งหมายความว่าผู้ใช้ไฟล์ YAML นี้จะต้องตระหนักถึงมัน

มีวิธี YAML ที่บริสุทธิ์ในการทำสิ่งนี้หรือไม่? หรือฉันจะต้องใช้การประมวลผลหลัง YAML เช่นการใช้การแทนที่ตัวแปรหรือการยกโครงสร้างย่อยบางประเภทโดยอัตโนมัติ ฉันกำลังดำเนินการหลังการประมวลผลแบบนั้นอยู่แล้วเพื่อจัดการกับกรณีการใช้งานอื่น ๆ อีกสองสามกรณีดังนั้นฉันจึงไม่รังเกียจมันเลย แต่ไฟล์ YAML ของฉันจะถูกเขียนโดยมนุษย์ไม่ใช่ที่สร้างขึ้นโดยเครื่องดังนั้นฉันจึงต้องการลดจำนวนกฎที่ผู้ใช้ของฉันต้องจดจำให้น้อยที่สุดนอกเหนือจากไวยากรณ์ YAML มาตรฐาน

ฉันต้องการที่จะทำสิ่งที่คล้ายคลึงกับแผนที่:

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

moresites: *sites
  Baz: www.baz.com

ฉันได้ค้นหาข้อมูลจำเพาะของ YAMLแล้ว แต่ไม่พบอะไรเลยฉันจึงสงสัยว่าคำตอบคือ "ไม่คุณทำสิ่งนี้ไม่ได้" แต่ถ้าใครมีไอเดียไหนจะดีมาก


แก้ไข:เนื่องจากไม่มีคำตอบฉันจึงสันนิษฐานว่าไม่มีใครเห็นสิ่งที่ฉันไม่ได้ระบุในข้อกำหนด YAML และไม่สามารถทำได้ที่เลเยอร์ YAML ดังนั้นฉันจึงเปิดคำถามเพื่อเป็นแนวคิดในการประมวลผล YAML เพื่อช่วยในเรื่องนี้เผื่อว่าใครจะพบคำถามนี้ในอนาคต


หมายเหตุ:ปัญหานี้อาจได้รับการแก้ไขด้วยการใช้ Anchors และ Aliases แบบมาตรฐานใน YAML ดูเพิ่มเติม: วิธีผสานอาร์เรย์ YAML
dreftymac

คำตอบ:


53

ประเภทคีย์การผสานน่าจะเป็นสิ่งที่คุณต้องการ ใช้<<คีย์การแมปพิเศษเพื่อระบุการผสานทำให้สามารถใช้นามแฝงในการแม็ป (หรือลำดับของนามแฝงดังกล่าว) เป็นตัวเริ่มต้นเพื่อรวมเข้ากับการแม็ปเดียว นอกจากนี้คุณยังสามารถลบล้างค่าอย่างชัดเจนหรือเพิ่มเพิ่มเติมที่ไม่มีอยู่ในรายการผสานได้

สิ่งสำคัญคือต้องสังเกตว่ามันทำงานร่วมกับการแมปไม่ใช่ลำดับเหมือนตัวอย่างแรก สิ่งนี้สมเหตุสมผลเมื่อคุณคิดเกี่ยวกับเรื่องนี้และตัวอย่างของคุณดูเหมือนว่ามันอาจจะไม่จำเป็นต้องเป็นลำดับต่อไป เพียงแค่เปลี่ยนค่าลำดับของคุณเป็นคีย์การแมปควรทำเคล็ดลับดังตัวอย่างต่อไปนี้ (ยังไม่ทดสอบ):

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

บางสิ่งที่สังเกตเห็น ประการแรกเนื่องจาก<<เป็นคีย์จึงสามารถระบุได้เพียงครั้งเดียวต่อโหนด ประการที่สองเมื่อใช้ลำดับเป็นค่าลำดับมีความสำคัญ สิ่งนี้ไม่สำคัญในตัวอย่างที่นี่เนื่องจากไม่มีค่าที่เกี่ยวข้อง แต่ควรทราบ


อ๊ะขอบคุณ! เป็นประโยชน์มาก มันน่าเสียดายที่มันใช้ไม่ได้กับซีเควนซ์ คุณคิดถูกที่ลำดับไม่สำคัญสำหรับตัวอย่างนี้ สิ่งที่ฉันมีคือชุดแนวความคิด แต่แผนที่นั้นใกล้เคียงกับลำดับมากกว่าการทำแผนที่ และโครงสร้างของสิ่งที่ฉันได้รับจากเรื่องนี้ (ซึ่งเป็นสาเหตุที่ฉันไม่ต้องการเพิ่มการซ้อนชั้นอื่นเพื่อผสานโครงสร้างของฉัน) ดังนั้นการมีการแมปที่ฉันต้องละเว้นค่า (null ทั้งหมด) จึงไม่ ไม่ได้ผลจริงๆ
เบ็น

3
ฉันไม่เห็นอะไรที่มันอยู่ในสเปคอย่างเป็นทางการ YAML ปัจจุบัน: yaml.org/spec/1.2/spec.html หน้านั้นไม่มีคำว่า "ผสาน" หรือข้อความ "<<" หรือวลี "ประเภทคีย์" ไวยากรณ์ << ทำงานในแพ็คเกจ Python yaml คุณรู้หรือไม่ว่าฉันสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับคุณสมบัติพิเศษเหล่านี้ได้จากที่ใด
เบ็น

1
ไม่ได้อยู่ในข้อมูลจำเพาะโดยตรง แต่อธิบายไว้ในที่เก็บแท็ก Schemas อื่นมีคำอธิบายทั่วไปและลิงก์ นอกจากปุ่มผสานแล้วยังมีชุดและชุดที่สั่ง อย่างไรก็ตาม YAML ถือว่าชุดเป็นประเภทของการทำแผนที่ (เช่นตัวอย่างข้างต้นสามารถนำไปใช้เป็นชุดได้) ภาษาของคุณอนุญาตให้คุณสลับคีย์กับค่าในการแมปผลลัพธ์หรือไม่ แม้ว่าคุณจะต้องใช้สิ่งนั้นด้วยตัวเอง แต่ฉันคิดว่ามันจะสะอาดกว่า อย่างน้อยคุณก็ต้องจัดกลุ่มข้อมูลทั้งหมดเข้าด้วยกันและ YAML ของคุณจะเป็นมาตรฐาน
kittemon

ชุดไม่แมปแม้ว่า; การแมปคือชุดของการเชื่อมโยงคีย์ - ค่า เมื่อฉันyaml.load(...)อยู่ใน Python ฉันจะได้พจนานุกรมเป็นตัวแทนของการแมป YAML ใช่มันง่ายที่จะโพสต์โพรเซสลงในเซต แต่ฉันต้องรู้ว่ามันเกิดขึ้น (และความซับซ้อนเชิงความหมายเมื่ออ่าน / เขียนไฟล์คอนฟิกจะสูงกว่ามากถ้ากฎคือ "เซตถูกเขียนเป็นแมปที่มีค่า null" ). เนื่องจากฉันต้องการการประมวลผลระหว่างyaml.load(...)และการใช้ข้อมูลที่เป็นผลลัพธ์ไม่ว่าฉันจะใช้<<หรือMERGEฉันอาจจะยึดติดกับMERGE(ซึ่งฉันได้ดำเนินการไปแล้วในตอนนี้)
เบ็น

2
ใช่ฉันพบว่าได้!!setผล แม้ว่าสำเร็จรูปที่คลุมเครือมากเกินไป ไฟล์เหล่านี้สร้างขึ้นเพื่อให้มนุษย์สามารถอ่าน / เขียนได้โดยผู้ที่ไม่จำเป็นต้องเป็นผู้เชี่ยวชาญของ YAML ผู้คนจะเขียนรายชื่อไซต์ของตนเป็นรายการ YAML จากนั้นต้องการรวมเข้าด้วยกันและต้องแปลงข้อมูลทั้งหมดเป็นชุดและอย่าลืมติดแท็กเป็นชุดอย่างชัดเจน ... ฉันมีโพสต์มาตรฐานอื่น ๆ อีกสองสามรายการ - การประมวลผลสิ่งพร้อมด้วยMERGEล่ะค่ะ ขอบคุณสำหรับความช่วยเหลือของคุณ!
เบ็น

17

ตามคำตอบก่อนหน้านี้ไม่มีการสนับสนุนในตัวสำหรับการขยายรายการใน YAML ฉันกำลังเสนอวิธีอื่นในการนำไปใช้ด้วยตัวคุณเอง พิจารณาสิ่งนี้:

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

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

สิ่งนี้จะถูกประมวลผลเป็น:

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

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

แนวคิดคือการรวมเนื้อหาของคีย์ที่ลงท้ายด้วย '+' กับคีย์ที่เกี่ยวข้องโดยไม่มี '+' ผมดำเนินการนี้ในหลามและเผยแพร่ ที่นี่

สนุก!


2
หมายเหตุ:ปัญหานี้อาจได้รับการแก้ไขด้วยการใช้ Anchors และ Aliases แบบมาตรฐานใน YAML ดูเพิ่มเติม: วิธีผสานอาร์เรย์ YAML
dreftymac

12
นี้หมายความว่าวิธีการนี้จะทำงานเฉพาะกับเครื่องมือที่แยกต่างหากที่ผสานและsites sites+ฉันหมายถึงเครื่องมือที่ผู้ใช้ต้องนำไปใช้เนื่องจากนี่ไม่ใช่yamlพฤติกรรมเริ่มต้น?
stan0

7

(ตอบคำถามของตัวเองในกรณีที่วิธีแก้ปัญหาที่ฉันใช้มีประโยชน์สำหรับทุกคนที่ค้นหาสิ่งนี้ในอนาคต)

หากไม่มีวิธี YAML ที่แท้จริงในการทำเช่นนี้ฉันจะใช้สิ่งนี้เป็น "การแปลงไวยากรณ์" ซึ่งอยู่ระหว่างตัวแยกวิเคราะห์ YAML และรหัสที่ใช้ไฟล์การกำหนดค่าจริง ดังนั้นแอปพลิเคชันหลักของฉันจึงไม่ต้องกังวลเลยเกี่ยวกับมาตรการหลีกเลี่ยงความซ้ำซ้อนที่เป็นมิตรกับมนุษย์และสามารถดำเนินการโดยตรงกับโครงสร้างที่เป็นผลลัพธ์

โครงสร้างที่ฉันจะใช้มีลักษณะดังนี้:

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

ซึ่งจะถูกเปลี่ยนให้เทียบเท่ากับ:

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

หรือด้วยแผนที่:

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

จะเปลี่ยนเป็น:

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

อีกอย่างเป็นทางการหลังจากที่เรียกตัวแยกวิเคราะห์ YAML ที่จะได้รับวัตถุพื้นเมืองจากไฟล์ config MERGEแต่ก่อนที่จะผ่านวัตถุที่จะได้ส่วนที่เหลือของแอพลิเคชันแอพลิเคชันของฉันจะเดินกราฟวัตถุที่กำลังมองหาการแมปที่มีปุ่มเดียว ค่าที่เกี่ยวข้องMERGEต้องเป็นรายการของรายการหรือรายการแผนที่ โครงสร้างย่อยอื่น ๆ เป็นข้อผิดพลาด

ในกรณี list-of-list แผนที่ทั้งหมดที่มีMERGEจะถูกแทนที่ด้วยรายการย่อยที่เรียงต่อกันตามลำดับที่ปรากฏ

ในกรณี list-of-maps แผนที่ทั้งหมดที่มีMERGEจะถูกแทนที่ด้วยแผนที่เดียวที่มีคู่คีย์ / ค่าทั้งหมดในแผนที่ย่อย ในกรณีที่มีการทับซ้อนกันในคีย์ระบบจะใช้ค่าจากแผนที่ลูกที่เกิดขึ้นล่าสุดในMERGEรายการ

ตัวอย่างที่ให้ไว้ข้างต้นไม่มีประโยชน์นักเนื่องจากคุณสามารถเขียนโครงสร้างที่ต้องการได้โดยตรง มีแนวโน้มที่จะปรากฏเป็น:

foo:
  MERGE:
    - *salt
    - *pepper

อนุญาตให้คุณสร้างรายการหรือแผนที่ที่มีทุกอย่างในโหนดsaltและpepperนำไปใช้ที่อื่น

(ฉันให้foo:แผนที่ภายนอกนั้นเพื่อแสดงว่าMERGEต้องเป็นคีย์เดียวในการแมปซึ่งหมายความว่าMERGEไม่สามารถปรากฏเป็นชื่อระดับบนสุดได้เว้นแต่จะไม่มีชื่อระดับบนสุดอื่น ๆ )


6

เพื่อชี้แจงบางอย่างจากคำตอบทั้งสองที่นี่สิ่งนี้ไม่ได้รับการสนับสนุนโดยตรงใน YAML สำหรับรายการ (แต่รองรับพจนานุกรมดูคำตอบของ kittemon)


หมายเหตุ:ปัญหานี้อาจได้รับการแก้ไขด้วยการใช้ Anchors และ Aliases แบบมาตรฐานใน YAML ดูเพิ่มเติม: วิธีผสานอาร์เรย์ YAML
dreftymac

5

หากต้องการปิดคำตอบของ Kittemon โปรดทราบว่าคุณสามารถสร้างการแมปด้วยค่า null โดยใช้ไวยากรณ์ทางเลือก

foo:
    << : myanchor
    bar:
    baz:

แทนไวยากรณ์ที่แนะนำ

foo:
    << : myanchor
    ? bar
    ? baz

เช่นเดียวกับคำแนะนำของ Kittemon สิ่งนี้จะช่วยให้คุณสามารถใช้การอ้างอิงไปยังจุดยึดภายในการทำแผนที่และหลีกเลี่ยงปัญหาลำดับ ฉันพบว่าตัวเองจำเป็นต้องทำสิ่งนี้หลังจากที่พบว่าคอมโพเนนต์ Symfony Yaml v2.4.4 ไม่ได้ทำการ reorgnize ? barไวยากรณ์


สิ่งที่ไม่myanchorดูอย่างไร
ssc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.