다른 곳에 YAML 파일을 어떻게 포함시킬 수 있습니까?
따라서 "A"와 "B"라는 두 개의 YAML 파일이 있으며 A의 내용을 B와 같이 기존 데이터 구조에 배열처럼 배열하거나 값과 같은 요소의 자식으로 삽입하고 싶습니다. 특정 해시 키의 경우.
이것이 가능합니까? 어떻게? 그렇지 않다면 규범 적 참조를 가리키는 포인터가 있습니까?
아니요, YAML에는 "import"또는 "include"문이 포함되어 있지 않습니다.
귀하의 질문은 Python 솔루션을 요구하지 않지만 PyYAML을 사용하는 솔루션이 있습니다.
PyYAML을 사용하면 커스텀 생성자 (예 :)를 !include
YAML 로더 에 연결할 수 있습니다 . 이 솔루션이 상대 및 절대 파일 참조를 지원하도록 설정할 수있는 루트 디렉토리를 포함 시켰습니다.
클래스 기반 솔루션
다음은 원래 응답의 전역 루트 변수를 피하는 클래스 기반 솔루션입니다.
메타 클래스를 사용하여 사용자 정의 생성자를 등록하는 유사하고 강력한 Python 3 솔루션에 대해서는이 요지 를 참조하십시오 .
import yaml
import os
class Loader(yaml.SafeLoader):
def __init__(self, stream):
self._root = os.path.split(stream.name)[0]
super(Loader, self).__init__(stream)
def include(self, node):
filename = os.path.join(self._root, self.construct_scalar(node))
with open(filename, 'r') as f:
return yaml.load(f, Loader)
Loader.add_constructor('!include', Loader.include)
예를 들면 :
foo.yaml
a: 1
b:
- 1.43
- 543.55
c: !include bar.yaml
bar.yaml
- 3.6
- [1, 2, 3]
이제 다음을 사용하여 파일을로드 할 수 있습니다.
>>> with open('foo.yaml', 'r') as f:
>>> data = yaml.load(f, Loader)
>>> data
{'a': 1, 'b': [1.43, 543.55], 'c': [3.6, [1, 2, 3]]}
Symfony의 YAML 버전을 사용하는 경우 다음 과 같이 가능합니다.
imports:
- { resource: sub-directory/file.yml }
- { resource: sub-directory/another-file.yml }
내가 아는 한 포함은 YAML에서 직접 지원되지 않지만 메커니즘을 직접 제공해야하지만 일반적으로 수행하기 쉽습니다.
파이썬 앱에서 YAML을 구성 언어로 사용 했으며이 경우 종종 다음과 같은 규칙을 정의합니다.
>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]
그런 다음 내 (파이썬) 코드에서 수행합니다.
import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
cfg.update(yaml.load(open(inc)))
유일한 단점은 include의 변수가 항상 main의 변수를 재정의하고 "include : 문이 main.yml 파일에 나타나는 위치를 변경하여 우선 순위를 변경할 수있는 방법이 없다는 것입니다.
약간 다른 점에서 YAML은 파일 기반 마크 업처럼 독점적으로 설계되지 않았으므로 포함을 지원하지 않습니다. AJAX 요청에 대한 응답으로 포함하면 포함이란 무엇을 의미합니까?
@Josh_Bode의 답변을 확장하여 여기에 자체 포함 된 하위 클래스라는 이점이있는 내 자신의 PyYAML 솔루션이 yaml.Loader
있습니다. 모듈 수준 전역 또는 yaml
모듈 의 전역 상태 수정에 의존하지 않습니다 .
import yaml, os
class IncludeLoader(yaml.Loader):
"""
yaml.Loader subclass handles "!include path/to/foo.yml" directives in config
files. When constructed with a file object, the root path for includes
defaults to the directory containing the file, otherwise to the current
working directory. In either case, the root path can be overridden by the
`root` keyword argument.
When an included file F contain its own !include directive, the path is
relative to F's location.
Example:
YAML file /home/frodo/one-ring.yml:
---
Name: The One Ring
Specials:
- resize-to-wearer
Effects:
- !include path/to/invisibility.yml
YAML file /home/frodo/path/to/invisibility.yml:
---
Name: invisibility
Message: Suddenly you disappear!
Loading:
data = IncludeLoader(open('/home/frodo/one-ring.yml', 'r')).get_data()
Result:
{'Effects': [{'Message': 'Suddenly you disappear!', 'Name':
'invisibility'}], 'Name': 'The One Ring', 'Specials':
['resize-to-wearer']}
"""
def __init__(self, *args, **kwargs):
super(IncludeLoader, self).__init__(*args, **kwargs)
self.add_constructor('!include', self._include)
if 'root' in kwargs:
self.root = kwargs['root']
elif isinstance(self.stream, file):
self.root = os.path.dirname(self.stream.name)
else:
self.root = os.path.curdir
def _include(self, loader, node):
oldRoot = self.root
filename = os.path.join(self.root, loader.construct_scalar(node))
self.root = os.path.dirname(filename)
data = yaml.load(open(filename, 'r'))
self.root = oldRoot
return data
파이썬 사용자의 경우 pyyaml-include를 사용해보십시오 .
설치
pip install pyyaml-include
용법
import yaml
from yamlinclude import YamlIncludeConstructor
YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir='/your/conf/dir')
with open('0.yaml') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
print(data)
다음과 같은 YAML 파일 이 있다고 가정 하십시오.
├── 0.yaml
└── include.d
├── 1.yaml
└── 2.yaml
1.yaml
의 내용 :
name: "1"
2.yaml
의 내용 :
name: "2"
이름으로 파일 포함
최상위 레벨에서 :
있었다면
0.yaml
:
!include include.d/1.yaml
우리는 얻을 것이다 :
{"name": "1"}
매핑에서 :
있었다면
0.yaml
:
file1: !include include.d/1.yaml
file2: !include include.d/2.yaml
우리는 얻을 것이다 :
file1:
name: "1"
file2:
name: "2"
순서대로 :
있었다면
0.yaml
:
files:
- !include include.d/1.yaml
- !include include.d/2.yaml
우리는 얻을 것이다 :
files:
- name: "1"
- name: "2"
ℹ 참고 :
파일 이름은 절대적 (
/usr/conf/1.5/Make.yml
) 또는 상대적 (../../cfg/img.yml
) 일 수 있습니다.
와일드 카드로 파일 포함
파일 이름에는 쉘 스타일 와일드 카드가 포함될 수 있습니다. 와일드 카드로 찾은 파일에서로드 된 데이터는 순서대로 설정됩니다.
있었다면 0.yaml
:
files: !include include.d/*.yaml
우리는 얻을 것이다 :
files:
- name: "1"
- name: "2"
ℹ 참고 :
- 의
Python>=3.5
경우 YAML 태그의recursive
인수 가 인 경우 패턴 은 모든 파일 및 0 개 이상의 디렉토리 및 하위 디렉토리와 일치합니다.!include
true
“**”
“**”
큰 디렉토리 트리에서 패턴을 사용하면 재귀 검색으로 인해 많은 시간이 소요될 수 있습니다.
recursive
인수 를 가능하게하기 위해 !include
태그를 Mapping
또는 Sequence
모드로 작성 합니다 :
Sequence
모드의 인수 :
!include [tests/data/include.d/**/*.yaml, true]
Mapping
모드의 인수 :
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}
불행히도 YAML은 이것을 표준으로 제공하지 않습니다.
그러나 Ruby를 사용하는 경우, Ruby YAML 라이브러리를 확장하여 원하는 기능을 제공하는 gem이 있습니다 : https://github.com/entwanderer/yaml_extend
@ maxy-B가 사용하는 솔루션이 훌륭하게 보인다고 생각합니다. 그러나 중첩 된 포함으로 성공하지 못했습니다. 예를 들어 config_1.yaml에 config_3.yaml이 포함 된 config_2.yaml이 있으면 로더에 문제가있었습니다. 그러나로드시 새 로더 클래스 자체를 가리키면 작동합니다! 특히 이전 _include 함수를 약간 수정 된 버전으로 바꾸는 경우 :
def _include(self, loader, node):
oldRoot = self.root
filename = os.path.join(self.root, loader.construct_scalar(node))
self.root = os.path.dirname(filename)
data = yaml.load(open(filename, 'r'), loader = IncludeLoader)
self.root = oldRoot
return data
반영하면 다른 의견에 동의합니다. 입력 스트림이 파일이 아닐 수도 있으므로 중첩로드는 일반적으로 yaml에 적합하지 않지만 매우 유용합니다!
어쩌면 이것이 당신에게 영감을 줄 수 있고 jbb 규칙에 맞춰보십시오.
https://docs.openstack.org/infra/jenkins-job-builder/definition.html#inclusion-tags
- job: name: test-job-include-raw-1 builders: - shell: !include-raw: include-raw001-hello-world.sh
표준 YAML 1.2에는 기본적으로이 기능이 포함되어 있지 않습니다. 그럼에도 불구하고 많은 구현들이 그렇게하기 위해 약간의 확장을 제공합니다.
Java와 snakeyaml:1.24
YAML 파일을 구문 분석 / 방출하는 Java 라이브러리로 달성하는 방법을 제시 하여 다음 목표를 달성하기 위해 사용자 정의 YAML 태그를 생성 할 수 있습니다 (여러 YAML 파일에 정의 된 테스트 스위트를로드하는 데 사용하고 있음을 볼 수 있습니다) 대상 test:
노드에 대한 포함 목록으로 작동하게했습니다 .)
# ... yaml prev stuff
tests: !include
- '1.hello-test-suite.yaml'
- '3.foo-test-suite.yaml'
- '2.bar-test-suite.yaml'
# ... more yaml document
다음은 !include
태그를 처리 할 수있는 단일 클래스 Java입니다 . 파일은 classpath (Maven resources 디렉토리)에서로드됩니다.
/**
* Custom YAML loader. It adds support to the custom !include tag which allows splitting a YAML file across several
* files for a better organization of YAML tests.
*/
@Slf4j // <-- This is a Lombok annotation to auto-generate logger
public class MyYamlLoader {
private static final Constructor CUSTOM_CONSTRUCTOR = new MyYamlConstructor();
private MyYamlLoader() {
}
/**
* Parse the only YAML document in a stream and produce the Java Map. It provides support for the custom !include
* YAML tag to split YAML contents across several files.
*/
public static Map<String, Object> load(InputStream inputStream) {
return new Yaml(CUSTOM_CONSTRUCTOR)
.load(inputStream);
}
/**
* Custom SnakeYAML constructor that registers custom tags.
*/
private static class MyYamlConstructor extends Constructor {
private static final String TAG_INCLUDE = "!include";
MyYamlConstructor() {
// Register custom tags
yamlConstructors.put(new Tag(TAG_INCLUDE), new IncludeConstruct());
}
/**
* The actual include tag construct.
*/
private static class IncludeConstruct implements Construct {
@Override
public Object construct(Node node) {
List<Node> inclusions = castToSequenceNode(node);
return parseInclusions(inclusions);
}
@Override
public void construct2ndStep(Node node, Object object) {
// do nothing
}
private List<Node> castToSequenceNode(Node node) {
try {
return ((SequenceNode) node).getValue();
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("The !import value must be a sequence node, but " +
"'%s' found.", node));
}
}
private Object parseInclusions(List<Node> inclusions) {
List<InputStream> inputStreams = inputStreams(inclusions);
try (final SequenceInputStream sequencedInputStream =
new SequenceInputStream(Collections.enumeration(inputStreams))) {
return new Yaml(CUSTOM_CONSTRUCTOR)
.load(sequencedInputStream);
} catch (IOException e) {
log.error("Error closing the stream.", e);
return null;
}
}
private List<InputStream> inputStreams(List<Node> scalarNodes) {
return scalarNodes.stream()
.map(this::inputStream)
.collect(toList());
}
private InputStream inputStream(Node scalarNode) {
String filePath = castToScalarNode(scalarNode).getValue();
final InputStream is = getClass().getClassLoader().getResourceAsStream(filePath);
Assert.notNull(is, String.format("Resource file %s not found.", filePath));
return is;
}
private ScalarNode castToScalarNode(Node scalarNode) {
try {
return ((ScalarNode) scalarNode);
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("The value must be a scalar node, but '%s' found" +
".", scalarNode));
}
}
}
}
}
Symfony를 사용하면 yaml을 처리하면 yaml 파일을 간접적으로 중첩시킬 수 있습니다. 트릭은 parameters
옵션 을 사용하는 것입니다. 예 :
common.yml
parameters:
yaml_to_repeat:
option: "value"
foo:
- "bar"
- "baz"
config.yml
imports:
- { resource: common.yml }
whatever:
thing: "%yaml_to_repeat%"
other_thing: "%yaml_to_repeat%"
결과는 다음과 같습니다.
whatever:
thing:
option: "value"
foo:
- "bar"
- "baz"
other_thing:
option: "value"
foo:
- "bar"
- "baz"
아마도 질문을 받았을 때 지원되지 않았지만 다른 YAML 파일을 하나로 가져올 수 있습니다.
imports: [/your_location_to_yaml_file/Util.area.yaml]
온라인 참조가 없지만 이것은 나를 위해 작동합니다.
참고 URL : https://stackoverflow.com/questions/528281/how-can-i-include-a-yaml-file-inside-another
'Programing' 카테고리의 다른 글
C에 화살표 (->) 연산자가 존재하는 이유는 무엇입니까? (0) | 2020.04.07 |
---|---|
CustomErrors mode =“끄기” (0) | 2020.04.07 |
선과 가로 축 사이의 각도를 계산하는 방법은 무엇입니까? (0) | 2020.04.07 |
홈 버튼처럼 작동하도록 뒤로 버튼 재정의 (0) | 2020.04.07 |
Font Awesome의 아이콘 색상을 변경할 수 있습니까? (0) | 2020.04.07 |