Refactor _prepare_template_tags routine.
This commit is contained in:
parent
8462db6e03
commit
036d339e70
1 changed files with 126 additions and 91 deletions
217
secretary.py
217
secretary.py
|
|
@ -182,7 +182,77 @@ class Renderer(object):
|
||||||
|
|
||||||
return zip_file
|
return zip_file
|
||||||
|
|
||||||
def _prepare_template_tags(self, xml_document):
|
|
||||||
|
@staticmethod
|
||||||
|
def _inc_node_tags_count(node, is_block=False):
|
||||||
|
""" Increase field count of node and its parents """
|
||||||
|
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for attr in ['field_count', 'block_count', 'var_count']:
|
||||||
|
if not hasattr(node, attr):
|
||||||
|
setattr(node, attr, 0)
|
||||||
|
|
||||||
|
node.field_count += 1
|
||||||
|
if is_block:
|
||||||
|
node.block_count += 1
|
||||||
|
else:
|
||||||
|
node.var_count += 1
|
||||||
|
|
||||||
|
Renderer._inc_node_tags_count(node.parentNode, is_block)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_jinja_tag(tag):
|
||||||
|
"""
|
||||||
|
Returns True is tag (str) is a valid jinja instruction tag.
|
||||||
|
"""
|
||||||
|
return re.findall(r'(?is)^{[{|%].*[%|}]}$', tag)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_block_tag(tag):
|
||||||
|
"""
|
||||||
|
Returns True is tag (str) is a jinja flow control tag.
|
||||||
|
"""
|
||||||
|
return re.findall(r'(?is)^{%[^{}]*%}$', tag)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _tags_in_document(document):
|
||||||
|
"""
|
||||||
|
Yields a list of available jinja instructions tags in document.
|
||||||
|
"""
|
||||||
|
tags = document.getElementsByTagName('text:text-input')
|
||||||
|
|
||||||
|
for tag in tags:
|
||||||
|
if not tag.hasChildNodes():
|
||||||
|
continue
|
||||||
|
|
||||||
|
content = tag.childNodes[0].data.strip()
|
||||||
|
if not Renderer._is_jinja_tag(content):
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield tag
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _census_tags(document):
|
||||||
|
"""
|
||||||
|
Make a census of all available jinja tags in document. We count all
|
||||||
|
the children tags nodes within their parents. This process is necesary
|
||||||
|
to automaticaly avoid generating invalid documents when mixing block
|
||||||
|
tags in differents parts of a document.
|
||||||
|
"""
|
||||||
|
for tag in Renderer._tags_in_document(document):
|
||||||
|
content = tag.childNodes[0].data.strip()
|
||||||
|
block_tag = re.findall(r'(?is)^{%[^{}]*%}$', content)
|
||||||
|
|
||||||
|
Renderer._inc_node_tags_count(tag.parentNode, block_tag)
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_document_tags(self, document):
|
||||||
""" Here we search for every field node present in xml_document.
|
""" Here we search for every field node present in xml_document.
|
||||||
For each field we found we do:
|
For each field we found we do:
|
||||||
* if field is a print field ({{ field }}), we replace it with a
|
* if field is a print field ({{ field }}), we replace it with a
|
||||||
|
|
@ -222,82 +292,65 @@ class Renderer(object):
|
||||||
</table>
|
</table>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.log.debug('Preparing template tags')
|
# -------------------------------------------------------------------- #
|
||||||
fields = xml_document.getElementsByTagName('text:text-input')
|
# We have to replace a node, let's call it "placeholder", with the
|
||||||
|
# content of our jinja tag. The placeholder can be a node with all its
|
||||||
|
# children. Node's "text:description" attribute indicates how far we
|
||||||
|
# can scale up in the tree hierarchy to get our placeholder node. When
|
||||||
|
# said attribute is not present, then we scale up until we find a
|
||||||
|
# common parent for this tag and any other tag.
|
||||||
|
# -------------------------------------------------------------------- #
|
||||||
|
self.log.debug('Preparing document tags')
|
||||||
|
self._census_tags(document)
|
||||||
|
|
||||||
# First, count secretary fields
|
for tag in self._tags_in_document(document):
|
||||||
for field in fields:
|
placeholder = tag
|
||||||
if not field.hasChildNodes():
|
content = tag.childNodes[0].data.strip()
|
||||||
continue
|
is_block = self._is_block_tag(content)
|
||||||
|
scale_to = tag.getAttribute('text:description').strip().lower()
|
||||||
|
|
||||||
field_content = field.childNodes[0].data.strip()
|
if content.lower().find('|markdown') > 0:
|
||||||
|
# Take whole paragraph when handling a markdown field
|
||||||
|
scale_to = 'text:p'
|
||||||
|
|
||||||
if not re.findall(r'(?is)^{[{|%].*[%|}]}$', field_content):
|
if scale_to:
|
||||||
# Field does not contains jinja template tags
|
if FLOW_REFERENCES.get(scale_to, False):
|
||||||
continue
|
placeholder = self._parent_of_type(
|
||||||
|
tag, FLOW_REFERENCES[scale_to]
|
||||||
|
)
|
||||||
|
|
||||||
is_block_tag = re.findall(r'(?is)^{%[^{}]*%}$', field_content)
|
new_node = self.create_text_node(document, content)
|
||||||
self.inc_node_fields_count(field.parentNode,
|
|
||||||
'block' if is_block_tag else 'variable')
|
|
||||||
|
|
||||||
# Do field replacement and moving
|
elif is_block:
|
||||||
for field in fields:
|
# expand up the placeholder until a shared parent is found
|
||||||
if not field.hasChildNodes():
|
while not placeholder.parentNode.field_count > 1:
|
||||||
continue
|
placeholder = placeholder.parentNode
|
||||||
|
|
||||||
field_content = field.childNodes[0].data.strip()
|
if placeholder:
|
||||||
|
new_node = self.create_text_node(document, content)
|
||||||
if not re.findall(r'(?is)^{[{|%].*[%|}]}$', field_content):
|
|
||||||
# Field does not contains jinja template tags
|
|
||||||
continue
|
|
||||||
|
|
||||||
is_block_tag = re.findall(r'(?is)^{%[^{}]*%}$', field_content)
|
|
||||||
discard = field
|
|
||||||
field_reference = field.getAttribute('text:description').strip().lower()
|
|
||||||
|
|
||||||
if re.findall(r'\|markdown', field_content):
|
|
||||||
# a markdown field should take the whole paragraph
|
|
||||||
field_reference = 'text:p'
|
|
||||||
|
|
||||||
if field_reference:
|
|
||||||
# User especified a reference. Replace immediate parent node
|
|
||||||
# of type indicated in reference with this field's content.
|
|
||||||
node_type = FLOW_REFERENCES.get(field_reference, False)
|
|
||||||
if node_type:
|
|
||||||
discard = self._parent_of_type(field, node_type)
|
|
||||||
|
|
||||||
jinja_node = self.create_text_node(xml_document, field_content)
|
|
||||||
|
|
||||||
elif is_block_tag:
|
|
||||||
# Find the common immediate parent of this and any other field.
|
|
||||||
while discard.parentNode.secretary_field_count <= 1:
|
|
||||||
discard = discard.parentNode
|
|
||||||
|
|
||||||
if discard is not None:
|
|
||||||
jinja_node = self.create_text_node(xml_document,
|
|
||||||
field_content)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
jinja_node = self.create_text_span_node(xml_document,
|
new_node = self.create_text_span_node(document, content)
|
||||||
field_content)
|
|
||||||
|
|
||||||
parent = discard.parentNode
|
placeholder_parent = placeholder.parentNode
|
||||||
if not field_reference.startswith('after::'):
|
if not scale_to.startswith('after::'):
|
||||||
parent.insertBefore(jinja_node, discard)
|
placeholder_parent.insertBefore(new_node, placeholder)
|
||||||
else:
|
else:
|
||||||
if discard.isSameNode(parent.lastChild):
|
if placeholder.isSameNode(placeholder_parent.lastChild):
|
||||||
parent.appendChild(jinja_node)
|
placeholder_parent.appendChild(new_node)
|
||||||
else:
|
else:
|
||||||
parent.insertBefore(jinja_node,
|
placeholder_parent.insertBefore(
|
||||||
discard.nextSibling)
|
new_node, placeholder.nextSibling
|
||||||
|
)
|
||||||
|
|
||||||
if field_reference.startswith(('after::', 'before::')):
|
if scale_to.startswith(('after::', 'before::')):
|
||||||
# Do not remove whole field container. Just remove the
|
# Don't remove whole field tag, only "text:text-input" container
|
||||||
# <text:text-input> parent node if field has it.
|
placeholder = self._parent_of_type(tag, 'text:p')
|
||||||
discard = self._parent_of_type(field, 'text:p')
|
placeholder_parent = placeholder.parentNode
|
||||||
parent = discard.parentNode
|
|
||||||
|
|
||||||
parent.removeChild(discard)
|
|
||||||
|
# Finally, remove the placeholder
|
||||||
|
placeholder_parent.removeChild(placeholder)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -323,7 +376,9 @@ class Renderer(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _encode_escape_chars(xml_text):
|
def _encode_escape_chars(xml_text):
|
||||||
# Replace line feed and/or tabs within text span entities.
|
"""
|
||||||
|
Replace line feed and/or tabs within text:span entities.
|
||||||
|
"""
|
||||||
find_pattern = r'(?is)<text:([\S]+?)>([^>]*?([\n|\t])[^<]*?)</text:\1>'
|
find_pattern = r'(?is)<text:([\S]+?)>([^>]*?([\n|\t])[^<]*?)</text:\1>'
|
||||||
for m in re.findall(find_pattern, xml_text):
|
for m in re.findall(find_pattern, xml_text):
|
||||||
replacement = m[1].replace('\n', '<text:line-break/>')
|
replacement = m[1].replace('\n', '<text:line-break/>')
|
||||||
|
|
@ -334,8 +389,10 @@ class Renderer(object):
|
||||||
|
|
||||||
|
|
||||||
def add_media_to_archive(self, media, mime, name=''):
|
def add_media_to_archive(self, media, mime, name=''):
|
||||||
"""Adds to "Pictures" archive folder the file in `media` and register
|
"""
|
||||||
it into manifest file."""
|
Adds to "Pictures" archive folder the file in `media` and register
|
||||||
|
it into manifest file.
|
||||||
|
"""
|
||||||
extension = None
|
extension = None
|
||||||
if hasattr(media, 'name') and not name:
|
if hasattr(media, 'name') and not name:
|
||||||
extension = path.splitext(media.name)
|
extension = path.splitext(media.name)
|
||||||
|
|
@ -440,10 +497,11 @@ class Renderer(object):
|
||||||
def _render_xml(self, xml_document, **kwargs):
|
def _render_xml(self, xml_document, **kwargs):
|
||||||
# Prepare the xml object to be processed by jinja2
|
# Prepare the xml object to be processed by jinja2
|
||||||
self.log.debug('Rendering XML object')
|
self.log.debug('Rendering XML object')
|
||||||
|
template_string = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.template_images = dict()
|
self.template_images = dict()
|
||||||
self._prepare_template_tags(xml_document)
|
self._prepare_document_tags(xml_document)
|
||||||
template_string = self._unescape_entities(xml_document.toxml())
|
template_string = self._unescape_entities(xml_document.toxml())
|
||||||
jinja_template = self.environment.from_string(template_string)
|
jinja_template = self.environment.from_string(template_string)
|
||||||
|
|
||||||
|
|
@ -545,29 +603,6 @@ class Renderer(object):
|
||||||
"""
|
"""
|
||||||
return xml_document.createTextNode(text)
|
return xml_document.createTextNode(text)
|
||||||
|
|
||||||
def inc_node_fields_count(self, node, field_type='variable'):
|
|
||||||
""" Increase field count of node and its parents """
|
|
||||||
|
|
||||||
if node is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not hasattr(node, 'secretary_field_count'):
|
|
||||||
setattr(node, 'secretary_field_count', 0)
|
|
||||||
|
|
||||||
if not hasattr(node, 'secretary_variable_count'):
|
|
||||||
setattr(node, 'secretary_variable_count', 0)
|
|
||||||
|
|
||||||
if not hasattr(node, 'secretary_block_count'):
|
|
||||||
setattr(node, 'secretary_block_count', 0)
|
|
||||||
|
|
||||||
node.secretary_field_count += 1
|
|
||||||
if field_type == 'variable':
|
|
||||||
node.secretary_variable_count += 1
|
|
||||||
else:
|
|
||||||
node.secretary_block_count += 1
|
|
||||||
|
|
||||||
self.inc_node_fields_count(node.parentNode, field_type)
|
|
||||||
|
|
||||||
|
|
||||||
def get_style_by_name(self, style_name):
|
def get_style_by_name(self, style_name):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue