List 如何合并YAML数组?
我想在YAML中合并数组,并通过ruby加载它们-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,您完全是在混淆视听 注意:对这个问题的另一个答案基本上是用。
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