Python:迭代 YAML 文件并输出层次结构中的所有相关设置

发布于 2025-01-19 06:48:27 字数 2852 浏览 0 评论 0原文

我是 python 新手,正在寻找将 YAML 文件导入 Python 并迭代它以收集应用程序特定实例的相关应用程序设置的最佳方法。

例如这个 YAML 结构:

UAT:
    Configuration:
    #config relevant to all servers on UAT
    - appSettings:
        AWSAccessKey: ExampleKey
        AWSSecretKey: ExampleSecret
        AWSRegion: ExampleRegion
    Servers:
    - Server1:
        #config relevant to all apps on UAT>Server1
        Configuration:
        - appSettings:
            Key1: true
            Key2: '123'
        Apps:
        - Engine1:
            #config relevant to all Apps of type UAT>Server1>Engine1
            version: 1.2
            appSettings:
                Key3: 'abc'
                Key4: 'def'
                Key5: 'abc-123'
            Instance:
            - Instance1:
                path: 'examplepath'
                appSettings:
                    Key6: 'A1B1C1'
                    Key7: true
            - Instance2:
                appSettings:
                    Key6: 'A2B2C2'
                    Key7: false
            - Instance3:
                appSettings:
                    Key6: 'A3B3C3'
                    Key7: true
        - Engine2:
            version: 'example'
            appSettings: 'example'          
        - Engine3:
            path: 'example'
            version: 'example'
            appSettings:  
    - Server2:
        Configuration:
        - AppSettings:
            Apps:
            - App1:
                Instance:
                - Instance1: 'example'
                - Instance2: 'example'
    - Server3: 'example'

我希望能够消化这个结构,例如获取 UAT 上 Server1 上 Engine1 的 Instance3 的所有相关应用程序设置。 UAT>Server1>Engine1>Instance3 的预期输出为:

        AWSAccessKey: ExampleKey
        AWSSecretKey: ExampleSecret
        AWSRegion: ExampleRegion
            Key1: true
            Key2: '123'
                Key3: 'abc'
                Key4: 'def'
                Key5: 'abc-123'
                    Key6: 'A3B3C3'
                    Key7: true

我不关心结果的格式,我只是希望能够吐出所有相关的键值对。

首先,我已将 YAML 文件作为字典导入,并且能够输出所有应用程序设置,但无法弄清楚如何指定我想要停止的特定级别。

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('Example.yml')

yaml = ruamel.yaml.YAML()
data = yaml.load(in_file)

def lookup(sk, d, path=[]):
   # lookup the values for key(s) sk return as list the tuple (path to the value, value)
   if isinstance(d, dict):
       for k, v in d.items():
           if k == sk:
               yield (path + [k], v)
           for res in lookup(sk, v, path + [k]):
               yield res
   elif isinstance(d, list):
       for item in d:
           for res in lookup(sk, item, path + [item]):
               yield res

for path, value in lookup("appSettings", data):
   print(value)

进一步研究这个问题,我不确定矩阵/数组是否比字典更好,因为它可以保持顺序?任何对此的帮助将不胜感激

I'm new to python and am looking for the best way to import a YAML file into Python and iterate through it to collect relevant appsettings for a specific instance of an app.

For example this YAML structure:

UAT:
    Configuration:
    #config relevant to all servers on UAT
    - appSettings:
        AWSAccessKey: ExampleKey
        AWSSecretKey: ExampleSecret
        AWSRegion: ExampleRegion
    Servers:
    - Server1:
        #config relevant to all apps on UAT>Server1
        Configuration:
        - appSettings:
            Key1: true
            Key2: '123'
        Apps:
        - Engine1:
            #config relevant to all Apps of type UAT>Server1>Engine1
            version: 1.2
            appSettings:
                Key3: 'abc'
                Key4: 'def'
                Key5: 'abc-123'
            Instance:
            - Instance1:
                path: 'examplepath'
                appSettings:
                    Key6: 'A1B1C1'
                    Key7: true
            - Instance2:
                appSettings:
                    Key6: 'A2B2C2'
                    Key7: false
            - Instance3:
                appSettings:
                    Key6: 'A3B3C3'
                    Key7: true
        - Engine2:
            version: 'example'
            appSettings: 'example'          
        - Engine3:
            path: 'example'
            version: 'example'
            appSettings:  
    - Server2:
        Configuration:
        - AppSettings:
            Apps:
            - App1:
                Instance:
                - Instance1: 'example'
                - Instance2: 'example'
    - Server3: 'example'

I would like to be able to digest this and for example get all the relevant appsettings for Instance3 of Engine1 on Server1 on UAT. The expected output for UAT>Server1>Engine1>Instance3 would be:

        AWSAccessKey: ExampleKey
        AWSSecretKey: ExampleSecret
        AWSRegion: ExampleRegion
            Key1: true
            Key2: '123'
                Key3: 'abc'
                Key4: 'def'
                Key5: 'abc-123'
                    Key6: 'A3B3C3'
                    Key7: true

I'm not concerned with the formatting of the outcome I would just like to be able to spit out all the relevant key value pairs.

As a start I have imported the YAML file as a dictionary and been able to output all of the app settings but cannot work out how to specify the specific level I would like to stop at.

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('Example.yml')

yaml = ruamel.yaml.YAML()
data = yaml.load(in_file)

def lookup(sk, d, path=[]):
   # lookup the values for key(s) sk return as list the tuple (path to the value, value)
   if isinstance(d, dict):
       for k, v in d.items():
           if k == sk:
               yield (path + [k], v)
           for res in lookup(sk, v, path + [k]):
               yield res
   elif isinstance(d, list):
       for item in d:
           for res in lookup(sk, item, path + [item]):
               yield res

for path, value in lookup("appSettings", data):
   print(value)

Looking further into this I am not sure if a matrix/array would be better than a dictionary as this maintains the order? Any help with this would be MUCH appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

聚集的泪 2025-01-26 06:48:27

我认为没有一种特殊的YAML格式会更好,这常常
与您想要在一起的事物有关。给定一个特定的结构
有一些规律性(像您一样),您应该能够摆脱想要的东西。

但是,您不会将此yaml加载到字典中。您可以加载此,而高级映射为
作为python词典创建。

为了达到目标instance3,您将使用:

data['UAT']['Servers'][0]['Server1']['Apps'][0]['Engine1']['Instance'][2]['Instance3']

您只需通过更改lookup而忽略所有列表/序列索引,但是
在匹配路径uat> engine1> Instance3时,您无法轻易忽略中间密钥(
寻找更容易的
uat>服务器> server1> apps> eNgire1> instance> instance3
反而)。但是你似乎想
如果该密钥的值是序列/列表,则跳过在路径中添加键。

一旦这样做,您可以将“当前路径”匹配到匹配的路径,当然
仅在您到目前为止所收集的时间:

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(in_file)

def lookup(d, sk, target, path=None):
    if path is None:
        path = []
    if target[:len(path)] != path:
        return
    if isinstance(d, dict):
        for k, v in d.items():
            if k == sk:
                if isinstance(v, dict):
                    for k1, v1 in v.items():
                        yield path + [k1], v1
                else:
                    yield path, v  # there is an appSetting that doesn't have a dict as value
            newpath = path[:] if isinstance(v, list) else path + [k]
            for res in lookup(v, sk, target, newpath):
                yield res
    elif isinstance(d, list):
        for item in d:
            for res in lookup(item, sk, target, path[:]):  # don't add item to path here, but still need a copy
                yield res

target = 'UAT>Server1>Engine1>Instance3'.split('>')
dout = {key[-1]: value for key, value in lookup(data, sk='appSettings', target=target)}
yaml.dump(dout, sys.stdout)

它给出:

AWSAccessKey: ExampleKey
AWSSecretKey: ExampleSecret
AWSRegion: ExampleRegion
Key1: true
Key2: '123'
Key3: 'abc'
Key4: 'def'
Key5: 'abc-123'
Key6: 'A3B3C3'
Key7: true

I don't think there is a particular YAML format that would work better, this often
has to do with what you want to be together. Given a particular structure that
has some regularity (like yours) you should be able to get out of it what you want.

However you don't load this YAML into a dictionary. You load this, and the toplevel mapping is
created as a Python dictionary.

In order to reach your target Instance3, you would use:

data['UAT']['Servers'][0]['Server1']['Apps'][0]['Engine1']['Instance'][2]['Instance3']

You simply leave out all the list/sequence indexes by changing your lookup, but
you cannot easily ignore intermediate keys when matching the path UAT>Server1>Engine1>Instance3 (
it would be easier to look for
UAT>Servers>Server1>Apps>Engine1>Instance>Instance3
instead). But you seem to want to
skip adding a key to your path if the value for that key is a sequence/list.

Once you do that you can match your "current path" to your path to match, of course
only for the length you have gathered so far:

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(in_file)

def lookup(d, sk, target, path=None):
    if path is None:
        path = []
    if target[:len(path)] != path:
        return
    if isinstance(d, dict):
        for k, v in d.items():
            if k == sk:
                if isinstance(v, dict):
                    for k1, v1 in v.items():
                        yield path + [k1], v1
                else:
                    yield path, v  # there is an appSetting that doesn't have a dict as value
            newpath = path[:] if isinstance(v, list) else path + [k]
            for res in lookup(v, sk, target, newpath):
                yield res
    elif isinstance(d, list):
        for item in d:
            for res in lookup(item, sk, target, path[:]):  # don't add item to path here, but still need a copy
                yield res

target = 'UAT>Server1>Engine1>Instance3'.split('>')
dout = {key[-1]: value for key, value in lookup(data, sk='appSettings', target=target)}
yaml.dump(dout, sys.stdout)

which gives:

AWSAccessKey: ExampleKey
AWSSecretKey: ExampleSecret
AWSRegion: ExampleRegion
Key1: true
Key2: '123'
Key3: 'abc'
Key4: 'def'
Key5: 'abc-123'
Key6: 'A3B3C3'
Key7: true
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文