/projects/python_templating/
'''Super advanced template processor
templates:
- single: <{identifier}>
- list/dict: <[identifier]> content <[/identifier]>
the list/dict identifiers can be nested.
'''
import re
# pattern for identifiers
__pattern_id = r'[a-zA-Z_][a-zA-Z_0-9]*'
# single pattern: <{identifier}>
pattern_single = r'\<\{(?P<identifier>' + __pattern_id + r')\}\>'
# list/dict pattern: <[identifier]> some content <[/identifier]>
pattern_nested = r'\<\[(?P<identifier>' + __pattern_id + \
r')\]\>\n?(?P<content>.*?)\<\[/(?P=identifier)\]\>'
def process(template, replaces):
'''Processes template string
template: string to be processed.
replaces: dictionary containing all the substitutions.
Entries for single identifiers are converted to strings and entries for
list/dict identifiers must be lists of dictionaries or again dictionaries.
The replace dictionary must have the same nested structure as the template.
'''
# process match object for nested patterns, by recursively calling process
def __replace_nested(m):
sub_replaces = replaces[m.group('identifier')]
if type(sub_replaces) is list:
sub_templates = [process(m.group('content'), repl)
for repl in sub_replaces]
return ''.join(sub_templates).rstrip()
elif type(sub_replaces) is dict:
return process(m.group('content'), sub_replaces)
else:
raise TypeError(
'Expected a list or a dict as value for the id: '
+ str(m.group('identifier'))
+ ', but found: '
+ str(type(sub_replaces)))
# process match object for single patterns
def __replace_single(m):
return str(replaces[m.group('identifier')])
# first process nested patterns
template = re.sub(pattern_nested, __replace_nested, template, flags=re.DOTALL)
# then process single patterns
return re.sub(pattern_single, __replace_single, template, flags=re.DOTALL)