List 如何合并YAML数组?

List 如何合并YAML数组?,list,data-structures,yaml,List,Data Structures,Yaml,我想在YAML中合并数组,并通过ruby加载它们- some_stuff: &some_stuff - a - b - c combined_stuff: <<: *some_stuff - d - e - f 一些东西:&一些东西 -a -b -c 组合_材料: 这是行不通的: 仅YAML规范支持映射合并,而不支持序列合并 通过使用合并键更新:2019-07-01 14:06:12,您完全是在混淆视听 注意:对这个问题的另一个答案基本上是用。

我想在YAML中合并数组,并通过ruby加载它们-

some_stuff: &some_stuff
 - a
 - b
 - c

combined_stuff:
  <<: *some_stuff
  - d
  - e
  - f
一些东西:&一些东西
-a
-b
-c
组合_材料:

这是行不通的:

  • 仅YAML规范支持映射合并,而不支持序列合并

  • 通过使用合并键更新:2019-07-01 14:06:12,您完全是在混淆视听
    • 注意:对这个问题的另一个答案基本上是用。
      • 更新后的答案提到了本答案中解决方案的替代方案。它已添加到中,另请参见下面的部分
    上下文 本文假设以下上下文:

    • python 2.7
    • python YAML解析器
    问题 lfender6445希望在一个YAML文件中合并两个或多个列表,并且 合并列表在解析时显示为一个单数列表

    解决方案(解决方案) 这可以通过简单地将YAML锚指定给映射来实现,其中 所需列表显示为映射的子元素。然而,对此有一些警告(见下文“陷阱”)

    在下面的示例中,我们有三个映射(
    list_-one、list_-two、list_-two
    )和三个锚 以及在适当情况下引用这些映射的别名

    当YAML文件加载到程序中时,我们得到了想要的列表,但是 加载后可能需要稍作修改(见下面的陷阱)

    例子 原始YAML文件 列表一:&id001 -a -b -c 列表二:&id002 -e -f -g 列表三:&id003 -h -我 -j 组合列表: -*id001 -*id002 -*id003 YAML.safe_负载后的结果 ##组合列表 [ [ “a”, “b”, “c” ], [ “e”, “f”, “g” ], [ “h”, “我”, “j” ] ] 陷阱
    • 这种方法产生一个嵌套的列表列表,它可能不是所需的确切输出,但可以使用展平方法进行后处理
    • 申请唯一性和声明顺序
    结论 这种方法允许使用YAML的别名和锚定特性创建合并列表

    虽然输出结果是列表的嵌套列表,但可以使用
    flatte
    方法轻松地转换

    另见 @Anthon更新的替代方法
    flatten
    方法示例
    • Javascript
      flatten
    • Ruby
      flatten
    • Python
      flatten

    在以下条件下,您可以合并映射,然后将其键转换为列表:

    • 如果您使用的是jinja2模板和
    • 如果项目顺序不重要
    一些东西:&一些东西
    a:
    b:
    c:
    组合_材料:
    
    如果您只需要将一个项目合并到一个列表中,您可以这样做

    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
    

    如果目标是运行一系列shell命令,则可以通过以下方式实现:

    # 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
    
    我一直在我的
    gitlab ci.yml
    上使用这个(回答@rink.attendant.6对这个问题的评论)


    我们用于支持从gitlab进行私有回购的
    requirements.txt
    的工作示例:

    .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...
    
    其中
    要求\u test.txt
    包含


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

    在python中启用合并数组的另一种方法是定义
    !展平标签。
    (这使用PyYAML,与上面Anthon的回答不同。在您无法控制备份中使用哪个包的情况下,这可能是必要的,例如,
    anyconfig

    导入yaml
    yaml.添加构造函数(“!展平”,构造展平列表)
    def flatten_序列(序列:yaml.Node)->迭代器[str]:
    “”“将嵌套序列展平为字符串列表
    嵌套结构始终是SequenceNode
    """
    如果isinstance(序列,yaml.ScalarNode):
    屈服值
    返回
    如果不是isinstance(序列,yaml.SequenceNode):
    raise TypeError(f“!PLANT”只能展平序列节点,不能展平{sequence}”)
    对于顺序中的el.value:
    如果isinstance(el,yaml.SequenceNode):
    展平序列的产量(el)
    elif isinstance(el,yaml.ScalarNode):
    产值
    其他:
    raise TypeError(f“!PLANTE”只能接受标量节点,而不是{el}”)
    def构造平面列表(加载程序:yaml.loader,节点:yaml.node)->list[str]:
    “”“制作平面列表,应与“!flant”一起使用”
    Args:
    加载器:未使用,但必须传递给'yaml.add\u构造函数`
    节点:传递的要展平的节点
    """
    返回列表(展平顺序(节点))
    
    这种递归展平利用PyYAML文档结构,它将所有数组解析为
    SequenceNode
    s,将所有值解析为
    ScalarNode
    s。 可以在以下测试函数中测试(和修改)该行为

    导入pytest
    def测试_展平_yaml():
    #单巢
    参数字符串=“”
    面包:&面包
    -吐司
    -面包
    鸡肉:&鸡肉
    -*面包
    午夜餐:!压扁
    -*鸡肉
    -*面包
    """
    参数=yaml.load(参数字符串)
    断言已排序(参数[“午夜晚餐])==已排序(
    [“吐司”、“面包”、“吐司”、“面包”]
    )
    
    以下是我如何在文件中实现它

    “合并列表”部分位于环境变量部分。我认为棘手的部分(也是很酷的部分)是我能够在
    &es env base
    中使用对
    *快照存储库路径的引用

    一般来说-更喜欢使用,因为它支持使用YAML
    *引用

    version: "3.7"
    
    ### ------------------------------------------------------------------
    ### Variables
    ### ------------------------------------------------------------------
    x-variables:
      exposed-port: &exposed-port 9200
      es-base: &es-base
        image: docker.elastic.co/elasticsearch/elasticsearch:7.9.1
        ulimits:
          memlock:
            soft: -1
            hard: -1
        networks:
          - elastic
      data-path: &data-path /usr/share/elasticsearch/data      
      snapshots-repository-path: &snapshots-repository-path /usr/share/elasticsearch/backup
      volume-snapshots-repository: &volume-snapshots-repository 
        - type: volume
          source: snapshots-repository
          target: *snapshots-repository-path  
      services-es-env: &es-env-base
        "cluster.name": "es-docker-cluster"
        "cluster.initial_master_nodes": "es01,es02"
        "bootstrap.memory_lock": "true"
        "ES_JAVA_OPTS": "-Xms512m -Xmx512m"
        "ELASTIC_PASSWORD": "esbackup-password"
        "xpack.security.enabled": "true"
        "path.repo": *snapshots-repository-path
    ### ------------------------------------------------------------------
    
    services:
      es01: # master
        <<: *es-base
        container_name: es01
        environment:
          <<: *es-env-base
          node.name: es01
          discovery.seed_hosts: es02
        volumes:
          - <<: *volume-snapshots-repository 
          - type: volume
            source: data01
            target: *data-path
        ports:
          - published: *exposed-port
            target: 9200
            protocol: tcp
            mode: host
    
      es02:
        <<: *es-base
        container_name: es02
        environment:
          <<: *es-env-base
          node.name: es02
          discovery.seed_hosts: es01
        volumes:
          - <<: *volume-snapshots-repository 
          - type: volume
            source: data02
            target: *data-path
    
    volumes:
      data01:
        driver: local
      data02:
        driver: local
      snapshots-repository:
        driver: local
    
    networks:
      elastic:
        driver: bridge
    
    版本:“3.7”
    ### ------------------------------------------------------------------
    ###变数
    ### ------------------------------------------------------------------
    x变量:
    前任
    list_one: &id001
       - a
       - b
       - c
    
      list_two: &id002
       - e
       - f
       - g
    
      list_three: &id003
       - h
       - i
       - j
    
      list_combined:
          - *id001
          - *id002
          - *id003
    ## list_combined
      [
        [
          "a",
          "b",
          "c"
        ],
        [
          "e",
          "f",
          "g"
        ],
        [
          "h",
          "i",
          "j"
        ]
      ]
    
    some_stuff: &some_stuff
     a:
     b:
     c:
    
    combined_stuff:
      <<: *some_stuff
      d:
      e:
      f:
    
    {{ combined_stuff | list }}
    
    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
    
    # 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
    
    .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...
    
    version: "3.7"
    
    ### ------------------------------------------------------------------
    ### Variables
    ### ------------------------------------------------------------------
    x-variables:
      exposed-port: &exposed-port 9200
      es-base: &es-base
        image: docker.elastic.co/elasticsearch/elasticsearch:7.9.1
        ulimits:
          memlock:
            soft: -1
            hard: -1
        networks:
          - elastic
      data-path: &data-path /usr/share/elasticsearch/data      
      snapshots-repository-path: &snapshots-repository-path /usr/share/elasticsearch/backup
      volume-snapshots-repository: &volume-snapshots-repository 
        - type: volume
          source: snapshots-repository
          target: *snapshots-repository-path  
      services-es-env: &es-env-base
        "cluster.name": "es-docker-cluster"
        "cluster.initial_master_nodes": "es01,es02"
        "bootstrap.memory_lock": "true"
        "ES_JAVA_OPTS": "-Xms512m -Xmx512m"
        "ELASTIC_PASSWORD": "esbackup-password"
        "xpack.security.enabled": "true"
        "path.repo": *snapshots-repository-path
    ### ------------------------------------------------------------------
    
    services:
      es01: # master
        <<: *es-base
        container_name: es01
        environment:
          <<: *es-env-base
          node.name: es01
          discovery.seed_hosts: es02
        volumes:
          - <<: *volume-snapshots-repository 
          - type: volume
            source: data01
            target: *data-path
        ports:
          - published: *exposed-port
            target: 9200
            protocol: tcp
            mode: host
    
      es02:
        <<: *es-base
        container_name: es02
        environment:
          <<: *es-env-base
          node.name: es02
          discovery.seed_hosts: es01
        volumes:
          - <<: *volume-snapshots-repository 
          - type: volume
            source: data02
            target: *data-path
    
    volumes:
      data01:
        driver: local
      data02:
        driver: local
      snapshots-repository:
        driver: local
    
    networks:
      elastic:
        driver: bridge