使用jinja2访问嵌套的YAML映射

时间:2014-12-31 15:33:15

标签: python yaml jinja2 pyyaml

我最近开始使用YAML和jinja2。我无法理解为什么我需要在jinja2模板中引用我的YAML映射的整个结构。

我有以下YAML文件

---
PROVIDERS:
    PROV1:
        int: ge-0/1/1
        ipv4: 10.0.1.1/30
    PROV2:
        int: ge-0/1/2
        ipv4: 10.0.1.2/30

这是我的jinja2模板

{%- for provider in PROVIDERS %}
    {{ provider }}
    {{ PROVIDERS[provider].int }}   <-- why not provider.int
    {{ PROVIDERS[provider].ipv4 }}  <-- why not provider.ipv4
{%- endfor %}

使用pyyaml进行解析可以得到(预期)输出

PROV2
ge-0/1/2
10.0.1.2/30
PROV1
ge-0/1/1
10.0.1.1/30

但为什么我必须使用PROVIDERS[provider].intprovider.int不起作用。

此外,我想知道我是否可以将其作为映射列表而不是嵌套映射:

---
PROVIDERS:
    - PROV1:
        int: ge-0/1/1
        ipv4: 10.0.1.1/30
    - PROV2:
        int: ge-0/1/2
        ipv4: 10.0.1.2/30

我试过这样做,但jinja2模板不再产生所需的输出。

1 个答案:

答案 0 :(得分:4)

这里有两件事需要考虑:

  1. 从YAML文档构建什么Python数据结构?
  2. 您的模板如何引用该数据结构的元素?
  3. 回答第1点很简单:

    >>> import yaml
    >>> from pprint import pprint
    >>> p1 = yaml.load("""
    ... ---
    ... PROVIDERS:
    ...     PROV1:
    ...         int: ge-0/1/1
    ...         ipv4: 10.0.1.1/30
    ...     PROV2:
    ...         int: ge-0/1/2
    ...         ipv4: 10.0.1.2/30
    ... """)
    >>> pprint(p1)
    {'PROVIDERS': {'PROV1': {'int': 'ge-0/1/1', 'ipv4': '10.0.1.1/30'},
                   'PROV2': {'int': 'ge-0/1/2', 'ipv4': '10.0.1.2/30'}}}
    

    您有一个包含单个项目的字典,其键为'PROVIDERS',其值为包含'PROV1''PROV2'键的字典,其值均为另一个字典。这是一个比你需要的更深层次的嵌套结构(稍后会详细介绍),但现在我们可以看到你的数据结构了,我们可以弄清楚你的模板发生了什么。

    这一行:

    {%- for provider in PROVIDERS %}
    

    迭代PROVIDERS(给定您的输出,显然是第二级嵌套字典,它是顶部键'PROVIDERS'的值级别字典)。由于您要重复的是密钥,因此您需要使用这些密钥来获取相关的值:

    {{ PROVIDERS[provider].int }}
    {{ PROVIDERS[provider].ipv4 }}
    

    为您的目的提供更简单的YAML文档:

    ---
    - id: PROV1
      int: ge-0/1/1
      ipv4: 10.0.1.1/30
    - id: PROV2
      int: ge-0/1/2
      ipv4: 10.0.1.2/30
    

    请注意,我们已经抛弃了冗余的单项映射,并将映射的二级映射替换为映射列表。我们再次检查:

    >>> p2 = yaml.load("""
    ... ---
    ... - id: PROV1
    ...   int: ge-0/1/1
    ...   ipv4: 10.0.1.1/30
    ... - id: PROV2
    ...   int: ge-0/1/2
    ...   ipv4: 10.0.1.2/30
    ... """)
    >>> pprint(p2)
    [{'int': 'ge-0/1/1', 'ipv4': '10.0.1.1/30', 'id': 'PROV1'},
     {'int': 'ge-0/1/2', 'ipv4': '10.0.1.2/30', 'id': 'PROV2'}]
    

    以下是您的模板如何使用此数据结构:

    {%- for provider in PROVIDERS %}
        {{ provider.id }}
        {{ provider.int }}
        {{ provider.ipv4 }}
    {%- endfor %}
    

    显然,您需要修改为模板提供PROVIDERS的代码,因为它现在是整个YAML文档所代表的顶级列表,而不是嵌套在里面的字典它