test in Nunjucks if a dict has key - nunjucks

Some of the test data have img some not.
I am new to Nunjucks and google does not find how to test if the record have key img?
I try the following:
{% for r in testdata %}
{% if r.img %} <img src="{{img}}" alt="{{r.heading}}">{% endif %}
....
{% endfor $}
But seems does not work.
I have also search the Nunjucks doc, but does not find has_key or some other info.
testdata:
-
type: G
TID: 567
heading: 泰國
alt1: Tailânia
source:
-
type: P
TID: 4
heading: Monteiro, Vicente
alt1: 韋思明
alt2: Monteiro, Vicente Joao
source: 物業登記局局長 (1998)
-
type: P
TID: 1
heading: Pires, Candida da Silva Antunes
alt1: 李淑華
source: 澳門大學法學院副教授, (1995)
img: P0001.jpg

{% if r.img is defined %} should also do the trick. – Lesha Ogonkov 3 hours ago

Related

AnsibleUndefinedVariable: No variable found with this name: region1a"}

I want to get the output of information after comparing whether the region is the capital?
Help me figure out how to use "lookup" correctly?
{% if capital == lookup('vars', item) %} yes {% else %} no {% endif %}
or
{% if capital.action == {{ item }} %} yes {% else %} no {% endif %}
I get the following error
failed: [localhost] (item=region1a) => {"ansible_loop_var": "item", "changed": false, "item": "region1a", "msg": AnsibleError: template error while templating string: expected token ':', got '}'
here {{ item }} is a variable = region1a
I have these variables
vars:
AllCountry:
- name1
- name2
name1:
- region1a
- region1b
name2:
- region2a
- region2b
capital:
- region1a
- region2a
what am I wrong about?
It seems to me like this is what you are looking to achieve:
{% if item in capital %} yes {% else %} no {% endif %}
But that is really not foolproof. Imagine you have two regions named the same in two countries and one is the capital of one of the countries when the other is not the capital of the other one, how would you do it here?
I would really go with a more tied kind of dictionary like:
countries:
country1:
regions:
- region1
- region2
- region3
capital: region1
country2:
regions:
- region4
- region5
capital: region5
But without your actual use case and what you are trying to build with all this, this is hard to advise on the right type of data structure to construct.

How to iterate through three lists in parallel in Yaml file

Need 3 variables to change on every iteration.
ver = [1,2,3]
tes = [a,b,c]
bet = [1a.2b.3c]
{% for v,t,b in ver,tes,bet %}
{{ v }} {{ t }} {{ b}}
{% endfor %}
o/p:
1 a 1a
2 b 2b
3 c 3c
I ran the same, got a very messy o/p. There should be only 3 iterations printing 3 variables in each iteration.
How can i perform the above operations using the for loop ? In the above case
Any suggestions on where I'm going wrong, would help Thanks !
You can use the following code:
{% for i in range([ver|count, tes|count, bet|count]|min) %}
{{ ver[i] }} {{ tes[i] }} {{ bet[i] }}
{% endfor %}
It uses only built in filters and functions:
count
min (to handle sequences with different length, similarly as zip in python)
range
Entire code in python:
import jinja2
ver = [1, 2, 3, 4]
tes = ['a', 'b', 'c']
bet = ['1a', '2b', '3c']
t = jinja2.Template('''{% for i in range([ver|count, tes|count, bet|count]|min) %}
{{ ver[i] }} {{ tes[i] }} {{ bet[i] }}
{% endfor %}
''')
print(t.render(ver=ver, tes=tes, bet=bet))
It looks like you need something that behaves like Python's zip function. Here's one option, in which we simply expose zip to the Jinja environment:
>>> import jinja2
>>> ver=[1,2,3]
>>> tes=['a','b','c']
>>> bet=['1a','2b','3c']
>>> t=jinja2.Template('''{% for v,t,b in zip(ver,tes,bet) %}
... {{ v }} {{ t }} {{ b}}
... {% endfor %}
... ''')
>>> t.environment.globals.update(zip=zip)
>>> print(t.render(ver=ver,tes=tes,bet=bet))
1 2 3
a b c
1a 2b 3c
>>>

Convert lines of file to dictionary in ansible

Have a file that contains line in a format like below:
category1 name=item1
category1 attributes=attr1, attr2
category1 name=item2
category1 attributes=attr1, attr2, attr3
category2 name=item1
category2 attributes=attr1
Looking to get a dictionary in ansible like below:
- category1:
- name: item1
attributes: [attr1, attr2]
- name: item2
attributes: [attr1, attr2, attr3]
- category2:
- name: item1
attributes: [attr1]
I was trying with jinja2 and below is what I get as of now. Problem is that the code is getting complicated after every step. Is there any way using filter or other methods that could produce the expected result with more readable code?
Code:
- set_fact:
converted_data: >-
{%- set res = dict() -%}
{%- for line in content.stdout_lines -%}
{%- set key_val = line.split(' ', 1) -%}
{%- set second_level = [] -%}
{%- if res[key_val[0]] is defined -%}
{%- set second_level = res[key_val[0]] -%}
{%- endif -%}
{%- set val_split = key_val[1].split('=') -%}
{%- set _ = second_level.append( dict({ val_split[0]: (val_split[1].split(',') | map('trim') | list) }) ) -%}
{%- set _ = res.update({key_val[0]: second_level}) -%}
{%- endfor -%}
{{ res }}
Produces:
category1:
- name:
- item1
- attributes:
- attr1
- attr2
- name:
- item2
- attributes:
- attr1
- attr2
- attr3
category2:
- name:
- item1
- attributes:
- attr1
I would strongly advise you to stop writing this in Jinja and switch to Python. It can be a lookup plugin, a module, or just a very simple script to read from stdin and output a json.
Jinja is not designed for algorithms. Whilst you can implement any efficiently computable function using the turing-complete Jinja2 template language, it's going to be very very painful for you and for anyone else reading your code.
If you do it in Python, you can add few tests (just define few 'test_case1', 'test_case2' functions inside your script and use pytest to run them). Without tests you never will get a stable code for all cases (like if some line is missing, or there is a reordering, or duplicates, etc).

access name of yaml items (pointer reference ?) in liquid template [duplicate]

This question already has answers here:
Iterate over hashes in liquid templates
(3 answers)
Closed 6 years ago.
Say I have yaml data like so :
fruit:
- apple:
- color: "green"
- taste: "bitter"
- banana:
- color: "yellow"
- taste: "sweet"
I would like to parse the list so as to get the printed result :
apple
banana
Is there some way to write a liquid template to achieve said result, without modifying my yaml data (because of course it could be fixed by changing it to name: "banana" and so on...)
{% for item in page.fruit %}
{{ item.?????? }}
{% endfor %}
Cheers
Ok I found the solution in the OP here. As the guy is noting, it is not particularly easy to guess as a newcomer to this train of (object-oriented ?) thought...
---
layout: default
title: qui l'eut cru ?
permalink: /fruits/
fruit:
- apple:
- color: "green"
- taste: "bitter"
- banana:
- color: "yellow"
- taste: "sweet"
---
{% for item in page.fruit %}
{% for browser in item %}
**root of the sublist:** {{browser[0]}}
**contents of the sublist:** {{browser[1]}}
{% endfor %}
{% endfor %}

Include different file in Jekyll depending on the locale

I'm trying to create my first Jekyll website and I'm encountering a problem designing the i18n part.
The different articles will be totally rewritten for each language, so each one will be a different post, no problems here. I actually have more difficulties with the text in my layout / includes.
Typically, for the menu, I was thinking doing something along these lines:
{% capture menu_location %}menu.{{ lang }}.html{% endcapture %}
{% include menu_location %}
like suggested here. But this gives me the following error :
Included file 'menu_location' not
found in _includes directory
Is it possible to use a variable for the include tag ? Do you have any other idea how I can do this ?
Thanks !
PS: Even if I have only 3 languages in mind for the moment, I won't do it with an if / elseif / else syntax ;)
What you are trying to do isn't possible without modifying Jekyll. The include filter they defined treats its parameter as a string, not as an expression.
I've created a couple bilingual sites with Jekyll in the past. I found that the cleanest solution was often storing locale-dependant variables inside _config.yml, and reference it when needed.
# _config.yml
...
locales:
en:
welcome_message: "Welcome to my site"
...
es:
welcome_message: "Bienvenido a mi sitio"
For every page I render, I need to know its locale. The simplest way of doing that is adding a locale field on the top yaml that page:
---
# a page or post (for example index.html)
...
locale: en
---
You can then get the current page locale by doing page.locale.
If you have divided your site in folders (/en/ for english, /es/ for spanish, and so on, you can use the page url to calculate the locale, so that you don't need to specify the locale on each page:
{% capture locale %}{{ page.url | truncate: 3, "" | remove: "/" }}{% endcapture %}
{% if locale == "" %}{% assign locale = "en" %}{% endif %}
For a page like /en/blog/, locale will be 'en'; for /fr/le-blog, it will be 'fr'. You will have to use that line in all the layouts and includes that need to use the locale, though.
You can then get localized texts like this:
{{ site.locales[locale].welcome_message }}
Or, if you prefer page.locale:
{{ site.locales[page.locale].welcome_message }}
Menus are the same; you can generate them from _config.yml, too:
# _config.yml
...
locales:
en:
nav:
- text: Welcome
url: /en/welcome
- text: Blog
url: /en/blog
layout: post
...
es:
nav:
- text: Bienvenido
url: /es/bienvenido
- text: Blog
url: /es/blog
layout: post
...
Then you can have a single menu.html that generates the right menu depending on the page locale:
{% capture locale %}{{ page.url | truncate: 3, "" | remove: "/" }}{% endcapture %}
{% if locale == "" %}{% assign locale = "en" %}{% endif %}
<nav>
<ul class="nav">
{% for link in site.locales[locale].nav %}
{% assign current = nil %}
{% if page.url == link.url or page.layout == link.layout %}
{% assign current = 'current' %}
{% endif %}
<li class="{% if forloop.first %}first{% endif %} {{ current }} {% if forloop.last %}last{% endif %}">
<a class="{{ current }}" href="{{ link.url }}">{{ link.text }}</a>
</li>
{% endfor %}
</ul>
</nav>
For using ´page.locale´ instead of ´locale´, just remove the first two lines and replace site.locales[locale].nav by site.locales[page.locale].nav
I hope this helps.
Regards!
How about creating a filter, wouldn't it be simpler? Something like:
<li>{{some_text_id|localize</li>

Resources