"""Cioset management."""
from re import sub as re_sub
from lxml import etree
from chrysalio.lib.utils import normalize_spaces, make_id
from cioprocessor.relaxng import RELAXNG_CIOSET
from .utils import special_unprotect
# =============================================================================
[docs]def cioset_update(original, values):
"""Update original Cioset XML according to values.
:type original: lxml.etree._ElementTree
:param original:
Initial content of the file as a XML DOM object.
:param dict values:
Values of the form.
:rtype: lxml.etree._ElementTree
"""
# Title
value = normalize_spaces(values['cioset_title'].replace(' ', '‧'))
title_elt = original.find(
'{{{0}}}title'.format(RELAXNG_CIOSET['namespace']))
if not value and title_elt is not None:
original.getroot().remove(title_elt)
elif value:
if title_elt is None:
title_elt = etree.Element('title')
original.getroot().insert(0, title_elt)
title_elt.text = value
# Division
namespaces = {'set': RELAXNG_CIOSET['namespace']}
for elt in original.xpath('//set:division', namespaces=namespaces):
num = int(elt.xpath(
'count(preceding::set:division|ancestor::set:division)',
namespaces=namespaces))
_update_title(values, 'division{0}'.format(num), elt)
# Resources, copies and values
for tag in ('resources', 'copies', 'values'):
for num, elt in enumerate(original.xpath(
'//set:{0}'.format(tag), namespaces=namespaces)):
_update_title(values, '{0}{1}'.format(tag, num), elt)
value = make_id(
values.get('cioset_{0}{1}_for'.format(tag, num), ''),
'class')
if value:
elt.set('for', value)
else:
elt.attrib.pop('for', None)
# Defines and values
for tag in ('define', 'value'):
for num, elt in enumerate(original.xpath(
'//set:{0}'.format(tag), namespaces=namespaces)):
elt.text = value2string(
elt, values.get('cioset_{0}{1}'.format(tag, num)))
return etree.ElementTree(etree.fromstring(re_sub(
r'<file>\s+<path>([^<]+)</path>\s+</file>',
r'<file><path>\1</path></file>',
special_unprotect(etree.tostring(
original, pretty_print=True, encoding='utf-8').decode('utf8')))))
# =============================================================================
[docs]def value2string(elt, value):
"""Convert a string value according to type ``type_``.
:type elt: lxml.etree.Element
:param elt:
DOM element owner of the value.
:param str value:
Type of the value.
:rtype: str
"""
type_ = elt.get('type')
value = value.replace('\r\n', '\n') if value else ''
if type_ == 'boolean':
value = value.strip() not in ('', 'false', 'False', '0')
return 'true' if value else 'false'
if type_ == 'text':
indent = ' ' * 2 * (int(elt.xpath('count(ancestor::*)')) + 1)
value = value.split('\n')
for num, line in enumerate(value):
line = normalize_spaces(line.replace(' ', '‧'))
value[num] = '{indent}{line}'.format(indent=indent, line=line)
return '\n{0}\n{1}'.format(
'\n'.join(value).rstrip(), indent[2:]) \
if ''.join(value).strip() else ''
return value.strip()
# =============================================================================
def _update_title(values, name, root_elt):
"""Update or remove a title.
:param dict values:
Values of the form.
:param str name:
Name of the value representing the title.
:type root_elt: lxml.etree.Element
:param root_elt:
DOM element owner of the title.
"""
value = normalize_spaces(
values.get('cioset_{0}'.format(name), '').replace(' ', '‧'))
title_elt = root_elt.find(
'{{{0}}}title'.format(RELAXNG_CIOSET['namespace']))
if not value and title_elt is not None:
root_elt.remove(title_elt)
elif value:
if title_elt is None:
title_elt = etree.Element('title')
root_elt.insert(0, title_elt)
title_elt.text = value