Có cú pháp YAML để chia sẻ một phần của danh sách hoặc bản đồ không?


94

Vì vậy, tôi biết tôi có thể làm điều gì đó như sau:

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

anotherlist: *sites

Và có sitelistanotherlistcả hai đều chứa www.foo.comwww.bar.com. Tuy nhiên, những gì tôi thực sự muốn là cho anotherlistđến cũng chứa www.baz.com, mà không cần phải lặp lại www.foo.comwww.baz.com.

Làm điều này khiến tôi gặp lỗi cú pháp trong trình phân tích cú pháp YAML:

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

anotherlist: *sites
  - www.baz.com

Chỉ sử dụng neo và bí danh, dường như không thể làm những gì tôi muốn nếu không thêm một cấp cấu trúc con khác, chẳng hạn như:

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

anotherlist:
  - *sites
  - www.baz.com

Có nghĩa là người sử dụng tệp YAML này phải biết về nó.

Có cách nào thuần túy YAML để làm điều gì đó như thế này không? Hay tôi sẽ phải sử dụng một số xử lý sau YAML, chẳng hạn như thực hiện thay thế biến hoặc tự động nâng một số loại cấu trúc con nhất định? Tôi đã thực hiện loại xử lý hậu kỳ đó để xử lý một vài trường hợp sử dụng khác, vì vậy tôi không hoàn toàn ác cảm với nó. Nhưng các tệp YAML của tôi sẽ được viết bởi con người, không phải do máy tạo ra, vì vậy tôi muốn giảm thiểu số lượng các quy tắc mà người dùng của tôi cần phải ghi nhớ dựa trên cú pháp YAML chuẩn.

Tôi cũng muốn có thể làm điều tương tự với bản đồ:

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

moresites: *sites
  Baz: www.baz.com

Tôi đã tìm kiếm thông qua thông số kỹ thuật YAML và không thể tìm thấy bất cứ điều gì, vì vậy tôi nghi ngờ câu trả lời chỉ là "không, bạn không thể làm điều này". Nhưng nếu bất kỳ ai có bất kỳ ý tưởng sẽ là tuyệt vời.


CHỈNH SỬA: Vì không có câu trả lời nào, tôi cho rằng không ai phát hiện ra bất cứ thứ gì tôi chưa có trong thông số YAML và điều này không thể thực hiện được ở lớp YAML. Vì vậy, tôi đang mở câu hỏi để lên ý tưởng cho việc xử lý sau YAML để giúp giải quyết vấn đề này, trong trường hợp có ai đó tìm thấy câu hỏi này trong tương lai.


Lưu ý: Vấn đề này cũng có thể được giải quyết bằng cách sử dụng Anchors và Bí danh tiêu chuẩn trong YAML. Xem thêm: Làm thế nào để hợp nhất các mảng YAML?
dreftymac

Câu trả lời:


53

Loại khóa hợp nhất có thể là những gì bạn muốn. Nó sử dụng một <<khóa ánh xạ đặc biệt để chỉ ra các hợp nhất, cho phép một bí danh cho một ánh xạ (hoặc một chuỗi các bí danh đó) được sử dụng như một trình khởi tạo để hợp nhất thành một ánh xạ duy nhất. Ngoài ra, bạn vẫn có thể ghi đè rõ ràng các giá trị hoặc thêm các giá trị khác không có trong danh sách hợp nhất.

Điều quan trọng cần lưu ý là nó hoạt động với ánh xạ chứ không phải chuỗi như ví dụ đầu tiên của bạn. Điều này có ý nghĩa khi bạn nghĩ về nó và ví dụ của bạn có vẻ như nó có thể không cần phải tuần tự. Chỉ cần thay đổi các giá trị trình tự của bạn thành các khóa ánh xạ sẽ thực hiện được mẹo, như trong ví dụ (chưa được kiểm tra) sau:

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

Một số điều cần lưu ý. Thứ nhất, vì <<là một khóa nên nó chỉ có thể được chỉ định một lần cho mỗi nút. Thứ hai, khi sử dụng một chuỗi làm giá trị, thứ tự có ý nghĩa. Điều này không quan trọng trong ví dụ ở đây, vì không có giá trị liên quan, nhưng nó đáng được lưu ý.


Ah cảm ơn bạn! Điều đó khá hữu ích. Tuy nhiên, thật tiếc là nó không hoạt động cho các trình tự. Bạn nói đúng rằng thứ tự không quan trọng đối với ví dụ này; những gì tôi có về mặt khái niệm là một tập hợp, nhưng ánh xạ đó chặt chẽ hơn nhiều với một chuỗi hơn là một ánh xạ. Và cấu trúc của những gì tôi nhận được từ điều này quan trọng (đó là lý do tại sao tôi không muốn chỉ thêm một lớp lồng khác để hợp nhất các cấu trúc của mình), vì vậy việc có một ánh xạ mà tôi cần phải bỏ qua (tất cả các giá trị null) không không thực sự hiệu quả.
Ben

3
Tôi không thấy bất kỳ điều gì trên đó trong thông số chính thức của YAML hiện tại: yaml.org/spec/1.2/spec.html . Trang đó không chứa từ "hợp nhất", cũng không phải văn bản "<<", cũng không có cụm từ "loại khóa". Tuy nhiên, cú pháp << không hoạt động trong gói Python yaml. Bạn có biết nơi tôi có thể tìm hiểu thêm về các loại tính năng bổ sung này không?
Ben

1
Nó không trực tiếp trong thông số kỹ thuật, nó được mô tả trong kho thẻ. Các Lược đồ khác có mô tả chung và liên kết. Bên cạnh các khóa hợp nhất, còn có các bộ và bộ có thứ tự; tuy nhiên, YAML coi tập hợp là một loại ánh xạ (ví dụ: ví dụ trên có thể được triển khai dưới dạng tập hợp). Ngôn ngữ của bạn có cho phép bạn hoán đổi các khóa với các giá trị trong ánh xạ kết quả không? Ngay cả khi bạn phải tự mình thực hiện điều đó, tôi nghĩ nó sẽ sạch hơn; ít nhất bạn sẽ có tất cả dữ liệu được nhóm lại với nhau và YAML của bạn sẽ là tiêu chuẩn.
kittemon

Tuy nhiên, tập hợp không phải là ánh xạ; ánh xạ là một tập hợp các liên kết khóa-giá trị. Khi tôi sử dụng yaml.load(...)Python, tôi nhận được một từ điển dưới dạng đại diện của ánh xạ YAML. Có, thật dễ dàng để xử lý hậu kỳ thành một tập hợp, nhưng tôi phải biết rằng điều đó đã xảy ra (và độ phức tạp ngữ nghĩa khi đọc / ghi các tệp cấu hình cao hơn nhiều nếu quy tắc là "các tập hợp được viết dưới dạng bản đồ có giá trị null" ). Cho rằng tôi cần xử lý hậu kỳ giữa yaml.load(...)và sử dụng dữ liệu kết quả cho dù tôi sử dụng <<hay MERGE, tôi có thể sẽ gắn bó với MERGE(mà tôi đã triển khai ngay bây giờ).
Ben

2
Vâng, tôi đã tìm thấy nó !!sethoạt động. Mặc dù vậy, quá nhiều bảng mẫu khó hiểu. Những tệp này được tạo ra để con người có thể đọc / ghi được, bởi những người không nhất thiết phải là chuyên gia YAML. Mọi người sẽ viết ra danh sách các trang web của họ dưới dạng danh sách YAML, sau đó muốn hợp nhất chúng và phải chuyển đổi toàn bộ thành một tập hợp VÀ hãy nhớ gắn thẻ rõ ràng nó thành một tập hợp ... Tôi có một vài bài đăng được tiêu chuẩn hóa khác- xử lý mọi thứ cùng với MERGEdù sao. Cám ơn sự giúp đở cuả bạn!
Ben

16

Như các câu trả lời trước đã chỉ ra, không có hỗ trợ tích hợp để mở rộng danh sách trong YAML. Tôi đang đưa ra một cách khác để tự thực hiện nó. Xem xét điều này:

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

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

Điều này sẽ được xử lý thành:

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

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

Ý tưởng là hợp nhất nội dung của khóa kết thúc bằng dấu '+' thành khóa tương ứng không có dấu '+'. Tôi đã triển khai điều này bằng Python và xuất bản ở đây .

Thưởng thức!


2
Lưu ý: Vấn đề này cũng có thể được giải quyết bằng cách sử dụng Anchors và Bí danh tiêu chuẩn trong YAML. Xem thêm: Làm thế nào để hợp nhất các mảng YAML?
dreftymac

11
Điều này có nghĩa là cách tiếp cận này chỉ hoạt động với một công cụ riêng biệt kết hợp sitessites+. Ý tôi là một công cụ phải được người dùng triển khai vì đây không phải là yamlhành vi mặc định ?
stan0

7

(Trả lời câu hỏi của riêng tôi trong trường hợp giải pháp tôi đang sử dụng hữu ích cho bất kỳ ai tìm kiếm điều này trong tương lai)

Không có cách nào thuần YAML để làm điều này, tôi sẽ thực hiện điều này như một "chuyển đổi cú pháp" nằm giữa trình phân tích cú pháp YAML và mã thực sự sử dụng tệp cấu hình. Vì vậy, ứng dụng cốt lõi của tôi không phải lo lắng về bất kỳ biện pháp tránh dư thừa thân thiện với con người nào và chỉ có thể hành động trực tiếp trên các cấu trúc kết quả.

Cấu trúc tôi sẽ sử dụng trông như thế này:

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

Điều này sẽ được chuyển đổi tương đương với:

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

Hoặc, với bản đồ:

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

Sẽ được chuyển đổi thành:

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

Chính thức hơn, sau khi gọi trình phân tích cú pháp YAML để lấy các đối tượng gốc từ tệp cấu hình, nhưng trước khi chuyển các đối tượng đến phần còn lại của ứng dụng, ứng dụng của tôi sẽ đi qua biểu đồ đối tượng để tìm ánh xạ có chứa khóa đơn MERGE. Giá trị được liên kết với MERGEphải là một danh sách các danh sách hoặc một danh sách các bản đồ; bất kỳ cấu trúc con nào khác đều là lỗi.

Trong trường hợp danh sách các danh sách, toàn bộ bản đồ chứa MERGEsẽ được thay thế bằng các danh sách con được nối với nhau theo thứ tự chúng xuất hiện.

Trong trường hợp danh sách bản đồ, toàn bộ bản đồ chứa MERGEsẽ được thay thế bằng một bản đồ duy nhất chứa tất cả các cặp khóa / giá trị trong bản đồ con. Khi có sự chồng chéo trong các khóa, giá trị từ bản đồ con xuất hiện cuối cùng trong MERGEdanh sách sẽ được sử dụng.

Các ví dụ nêu trên không hữu ích lắm, vì bạn có thể viết trực tiếp cấu trúc mà bạn muốn. Nó có nhiều khả năng xuất hiện dưới dạng:

foo:
  MERGE:
    - *salt
    - *pepper

Cho phép bạn tạo một danh sách hoặc bản đồ chứa mọi thứ trong các nút saltpepperđược sử dụng ở những nơi khác.

(Tôi tiếp tục đưa foo:bản đồ bên ngoài đó để hiển thị rằng đó MERGEphải là khóa duy nhất trong ánh xạ của nó, có nghĩa là nó MERGEkhông thể xuất hiện dưới dạng tên cấp cao nhất trừ khi không có tên cấp cao nhất nào khác)


6

Để làm rõ điều gì đó từ hai câu trả lời ở đây, điều này không được hỗ trợ trực tiếp trong YAML cho danh sách (nhưng nó được hỗ trợ cho từ điển, xem câu trả lời của kittemon).


Lưu ý: Vấn đề này cũng có thể được giải quyết bằng cách sử dụng Anchors và Bí danh tiêu chuẩn trong YAML. Xem thêm: Làm thế nào để hợp nhất các mảng YAML?
dreftymac

5

Để lấy lại câu trả lời của Kittemon, hãy lưu ý rằng bạn có thể tạo ánh xạ với giá trị rỗng bằng cú pháp thay thế

foo:
    << : myanchor
    bar:
    baz:

thay vì cú pháp được đề xuất

foo:
    << : myanchor
    ? bar
    ? baz

Giống như gợi ý của Kittemon, điều này sẽ cho phép bạn sử dụng tham chiếu đến các neo trong ánh xạ và tránh vấn đề về trình tự. Tôi thấy mình cần phải làm điều này sau khi phát hiện ra rằng thành phần Symfony Yaml v2.4.4 không nhận dạng lại ? barcú pháp.


những gì hiện myanchorcái nhìn như thế nào?
ssc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.