programing

YAML 어레이를 Marge하는 방법

css3 2023. 4. 10. 22:09

YAML 어레이를 Marge하는 방법

YAML에서 어레이를 Marge하여 Ruby로 로드하고 싶습니다.

some_stuff: &some_stuff
 - a
 - b
 - c

combined_stuff:
  <<: *some_stuff
  - d
  - e
  - f

은 합된음음음음음음음음음음음음음 as as as as as as as 로 해 주세요[a,b,c,d,e,f]

오류 발생: 블록 매핑을 구문 분석하는 동안 예상된 키를 찾을 수 없습니다.

YAML에서 어레이를 Marge하려면 어떻게 해야 합니까?

일련의 셸 명령어를 실행하는 것이 목적이라면 다음과 같이 실행할 수 있습니다.

# note: no dash before commands
some_stuff: &some_stuff |-
    a
    b
    c

combined_stuff:
  - *some_stuff
  - d
  - e
  - f

이는 다음과 같습니다.

some_stuff: "a\nb\nc"

combined_stuff:
  - "a\nb\nc"
  - d
  - e
  - f

는 이것을 의 가걸 my my 하고 있다.gitlab-ci.yml(answer@rink.at에서 확인).


「 」를 서포트하기 위해서 사용하는 예requirements.txtgitlab의 개인 저장소가 있습니다.

.pip_git: &pip_git
- git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "ssh://git@gitlab.com"
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts

test:
    image: python:3.7.3
    stage: test
    script:
        - *pip_git
        - pip install -q -r requirements_test.txt
        - python -m unittest discover tests

use the same `*pip_git` on e.g. build image...

서 ''는requirements_test.txt아, 아, 아, 아, 아, 아, 아, 아, 아, 아.

-e git+ssh://git@gitlab.com/example/example.git@v0.2.2#egg=example

이 조작은 동작하지 않습니다.

  1. Merge는 매핑의 YAML 사양에서만 지원되며 시퀀스에서는 지원되지 않습니다.

  2. 수 있는 입니다.<< 구분자 "/값 구분자"가 지정됩니다.:참조가 되고 동일한 들여쓰기 수준에서 목록을 계속하는 값입니다.

이것은 올바른 YAML이 아닙니다.

combine_stuff:
  x: 1
  - a
  - b

따라서 이 예제 구문은 YAML 확장 제안서로서도 의미가 없습니다.

여러 어레이를 병합하는 등의 작업을 수행할 경우 다음과 같은 구문을 고려할 수 있습니다.

combined_stuff:
  - <<: *s1, *s2
  - <<: *s3
  - d
  - e
  - f

서 ''는s1,s2,s3 하고 되어 있지 않음)의이며, 그 후 (「」 「」 「Marge」 「」, 「」 「Marge」, 「」, 「」, 「」를 가지고 있습니다.d,e ★★★★★★★★★★★★★★★★★」f거기에 덧붙입니다.그러나 YAML은 이러한 구조의 깊이를 먼저 해결하고 있기 때문에 Marge Key 처리 중에는 실제 컨텍스트를 사용할 수 없습니다.처리한 값(고정 시퀀스)을 부가할 수 있는 어레이/리스트가 없습니다.

@dreftymac의 제안대로 어프로치를 취할 수 있지만, 이것은 어떤 중첩된 시퀀스를 평탄하게 할 필요가 있다는 큰 단점이 있습니다(로드된 데이터 구조의 루트에서 부모 시퀀스로의 「패스」를 아는 것).또는 로드된 데이터 구조를 반복적으로 이동하여 중첩된 배열/목록을 검색하고 모든 목록을 무차별적으로 평탄화시킵니다.

IMO는 태그를 사용하여 평탄화하는 데이터 구조를 로드하는 것이 좋습니다.이를 통해 평탄화해야 할 것과 그렇지 않은 것을 명확하게 나타낼 수 있으며, 평탄화가 로드 중에 수행되는지 또는 접근 중에 수행되는지 여부를 완전히 제어할 수 있습니다.어느 쪽을 선택할지는 구현의 용이성과 시간과 스토리지 공간의 효율성의 문제입니다.머지기능의 실장에 필요한 것과 같은 트레이드오프이며, 항상 최적인 솔루션은 없습니다.

my :: 제ruamel.yaml브루트 포스 머지Python dicts 라 、 Maggedictes 、 Python dicts 。이 병합은 사전에 수행해야 하며 데이터를 복제(공간 비효율적)하지만 값 검색 속도가 빠릅니다.라운드 트립 로더를 사용하는 경우 Marge를 Marge하지 않고 덤프할 수 있으므로 Marge를 개별적으로 유지해야 합니다.라운드 트립 로딩의 결과로 로드된 dict와 같은 데이터 구조는 공간 효율이 높지만 marge에서 dict 자체에서 찾을 수 없는 키를 검색해야 하기 때문에 액세스 속도가 느립니다(그리고 이것은 캐시되지 않으므로 매번 수행해야 합니다).물론 비교적 작은 구성 파일에는 이러한 고려 사항이 그다지 중요하지 않습니다.


가 붙은 에 대해 합니다.flatten 및가 붙은 하는 온 더 플라이toflatten이하여 YAML 수 다음 2개의 태그를 사용하여 YAML 파일을 얻을 수 있습니다.

l1: &x1 !toflatten
  - 1 
  - 2
l2: &x2
  - 3 
  - 4
m1: !flatten
  - *x1
  - *x2
  - [5, 6]
  - !toflatten [7, 8]

(플로우 vs 블록 스타일 시퀀스의 사용은 완전히 임의이며 로드된 결과에 영향을 미치지 않습니다.)

할 때m1해서 '', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다 거예요.toflatten단, 다른 목록(에일리어스 여부)을 단일 항목으로 표시합니다.

Python 코드로 이를 달성할 수 있는 방법 중 하나는 다음과 같습니다.

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)

출력:

1
2
[3, 4]
[5, 6]
7
8

보시다시피 평탄화가 필요한 시퀀스에서는 태그가 달린 시퀀스의 에일리어스를 사용하거나 태그가 달린 시퀀스를 사용할 수 있습니다.YAML에서는 다음 작업을 수행할 수 없습니다.

- !flatten *x2

즉, 고정 시퀀스에 태그를 붙이면 본질적으로 다른 데이터 구조가 되기 때문입니다.

YAML 머지 키와 같은 마법이 진행되는 것보다 명시적인 태그를 사용하는 이 IMO에 더 좋습니다.<<이 있는 YAML , 그 는, 를 실시할 필요가 <<예를 들어 C 연산자를 영어(또는 기타 자연어)로 설명에 매핑할 때 병합 키 역할을 하지 않는 것이 좋습니다.

갱신일 : 2019-07-01 14:06:12

  • 참고: 이 질문에 대한 또 다른 답변은 대체 접근법에 대한 업데이트를 통해 대폭 수정되었습니다.
    • 이 갱신된 답변에서는 이 답변의 회피책의 대안이 제시되어 있습니다.아래의 '또한 참조' 섹션에 추가되어 있습니다.

맥락

이 투고에서는, 다음의 콘텍스트를 상정하고 있습니다.

  • python 2.7
  • python YAML 파서

문제

lfender6445는 YAML 파일 내의 여러 목록을 Marge하고 이러한 Marge된 목록을 해석할 때 하나의 단일 목록으로 표시하려고 합니다.

솔루션 (회피책)

이것은 YAML 앵커를 매핑에 할당하는 것만으로 얻을 수 있습니다.이 매핑에서는 원하는 리스트가 매핑의 하위 요소로 표시됩니다.그러나 여기에는 경고 사항이 있습니다("함정" 인프라 참조).

의 매핑하다, 3개의 매핑)이 .list_one, list_two, list_three3개의 앵커와 에일리어스(해당하는 경우 이들 매핑을 참조).

프로그램에 YAML 파일이 로드되면 원하는 목록을 얻을 수 있지만 로드 후 약간의 수정이 필요할 수 있습니다(아래 함정 참조).

원본 YAML 파일

list_1: &id001- a- b(c)
list_2: &id002(e)(f)(g)
list_3: &id003- h- i(j).
list_filename:
(*id001).(*id002).(*id003).

YAML.safe_load 후 결과

## 리스트_개요[["a","b","c"],["e","f","g"],["h",'나',"j"]]

함정

  • 이 접근방식은 리스트의 네스트 리스트를 생성합니다.이 리스트는 원하는 정확한 출력은 아닐 수 있지만, 이것은 평탄한 방법을 사용하여 포스트 리셋할 수 있습니다.
  • YAML 앵커 및 에일리어스에 대한 일반적인 경고는 고유성 및 선언 순서에 적용됩니다.

결론

이 방법을 사용하면 YAML의 에일리어스 및 앵커 기능을 사용하여 Marge 목록을 작성할 수 있습니다.

이지만, 은 「」, 「」를 해 간단하게 할 수 .flatten★★★★★★ 。

「 」를 참조해 주세요.

@Anthon에 의한 대체 접근법 갱신

의 예flatten

하나의 항목만 목록에 병합해야 하는 경우 다음을 수행할 수 있습니다.

fruit:
  - &banana
    name: banana
    colour: yellow

food:
  - *banana
  - name: carrot
    colour: orange

그 결과

fruit:
  - name: banana
    colour: yellow

food:
  - name: banana
    colour: yellow
  - name: carrot
    colour: orange

또 다른 은 python을 입니다.!flattenPyYAML을 사용하다수 백엔드에서 사용되는 패키지)에합니다.anyconfig를 참조해 주세요.

import yaml

yaml.add_constructor("!flatten", construct_flat_list)

def flatten_sequence(sequence: yaml.Node) -> Iterator[str]:
    """Flatten a nested sequence to a list of strings
        A nested structure is always a SequenceNode
    """
    if isinstance(sequence, yaml.ScalarNode):
        yield sequence.value
        return
    if not isinstance(sequence, yaml.SequenceNode):
        raise TypeError(f"'!flatten' can only flatten sequence nodes, not {sequence}")
    for el in sequence.value:
        if isinstance(el, yaml.SequenceNode):
            yield from flatten_sequence(el)
        elif isinstance(el, yaml.ScalarNode):
            yield el.value
        else:
            raise TypeError(f"'!flatten' can only take scalar nodes, not {el}")

def construct_flat_list(loader: yaml.Loader, node: yaml.Node) -> List[str]:
    """Make a flat list, should be used with '!flatten'

    Args:
        loader: Unused, but necessary to pass to `yaml.add_constructor`
        node: The passed node to flatten
    """
    return list(flatten_sequence(node))

문서 을 PyYAML로 합니다.SequenceNode및 을 ""로 지정합니다.ScalarNode은 다음 기능에서 수정 수 있습니다. 동작은 다음 테스트 기능으로 테스트(및 수정)할 수 있습니다.

import pytest
def test_flatten_yaml():
    # single nest
    param_string = """
    bread: &bread
      - toast
      - loafs
    chicken: &chicken
      - *bread
    midnight_meal: !flatten
      - *chicken
      - *bread
    """
    params = yaml.load(param_string)
    assert sorted(params["midnight_meal"]) == sorted(
        ["toast", "loafs", "toast", "loafs"]
    )

다음과 같은 경우 매핑을 병합한 후 해당 키를 목록으로 변환할 수 있습니다.

  • jinja2 템플리트를 사용하고 있다면
  • 아이템 순서가 중요하지 않은 경우
some_stuff: &some_stuff
 a:
 b:
 c:

combined_stuff:
  <<: *some_stuff
  d:
  e:
  f:

{{ combined_stuff | list }}

언급URL : https://stackoverflow.com/questions/24090177/how-to-merge-yaml-arrays