You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
6.9 KiB

4 years ago
# vim: fileencoding=utf-8
#
from .base_format import BaseFormat
from pyparsing import originalTextFor, Literal, Word, printables, OneOrMore,\
Optional
from collections import OrderedDict
try:
from lxml.etree import Element, SubElement, ElementTree, tostring
except ImportError:
from xml.etree.ElementTree import Element, SubElement, ElementTree, \
tostring
class XMLXfceFormat(BaseFormat):
FORMAT = 'xml_xfce'
4 years ago
def __init__(self, document_text: str, ignore_comments=False):
processing_methods = OrderedDict({'channel': self._channel,
'property': self._property,
'value': self._value,
'unknown': self._unknown})
super().__init__(processing_methods)
self._initialize_parser()
if document_text == '':
self._document_dictionary = OrderedDict()
else:
self._parse_xml_to_dictionary(document_text)
def _initialize_parser(self):
action_symbols = (Literal('!') | Literal('-'))
name = originalTextFor(OneOrMore(Word(printables)))
self._node_name = Optional(action_symbols)('action') + name('name')
# Кортежи с названиями атрибутов различных элементов.
self._ELEMENT_ATTRIBUTES = ('tag', 'name', 'type', 'value')
self._CHANNEL_ATTRIBUTES = ('tag', 'name', 'version')
self._VALUE_ATTRIBUTES = ('tag', 'type', 'value')
def _property(self, xml_element):
try:
parsing_result = self._node_name.parseString(
xml_element.attrib['name']
)
element_name = (parsing_result.action,
xml_element.tag,
parsing_result.name,
xml_element.attrib['type'])
except Exception:
# Какая-то обработка ошибки.
return OrderedDict()
if xml_element.attrib['type'] == 'empty':
output = OrderedDict()
for child in xml_element:
child_value = self._processing_methods.get(child.tag,
self._unknown
)(child)
output.update(child_value)
elif xml_element.attrib['type'] == 'array':
output = []
for child in xml_element:
child_value = self._processing_methods.get(child.tag,
self._unknown
)(child)
output.append(child_value)
else:
try:
output = xml_element.attrib['value']
except KeyError:
# Какая-то обработка ошибки.
return OrderedDict()
return OrderedDict({element_name: output})
def _value(self, xml_element):
try:
value = (xml_element.tag,
xml_element.attrib['type'],
xml_element.attrib['value'])
except KeyError:
# Какая-то обработка ошибки.
return ('',)
return value
def _channel(self, xml_element):
output_dictionary = OrderedDict()
try:
parsing_result = self._node_name.parseString(
xml_element.attrib['name']
)
element_name = (parsing_result.action,
xml_element.tag,
parsing_result.name,
xml_element.attrib['version'])
except Exception:
# Какая-то обработка ошибки.
return OrderedDict()
for child in xml_element:
item_to_add = self._processing_methods.get(child.tag,
self._unknown)(child)
output_dictionary.update(item_to_add)
return OrderedDict({element_name: output_dictionary})
def _unknown(self, xml_element):
# Действия если элемент неизвестен.
element_name = ('', xml_element.tag)
return OrderedDict({element_name: 'Unknown element'})
@property
def document_text(self):
4 years ago
channel = next(iter(self._document_dictionary.keys()))
channel_head = OrderedDict(
{key: value for key, value in
zip(self._CHANNEL_ATTRIBUTES, channel[1:])}
)
root = Element(channel_head.pop('tag'), **channel_head)
self._build_section(root, self._document_dictionary[channel])
document_tree = ElementTree(root)
xml_document = tostring(document_tree,
encoding="UTF-8",
xml_declaration=True,
pretty_print=True).decode()
return xml_document
def _build_section(self, current_element, dictionary):
for dict_element in dictionary.keys():
element_head = OrderedDict({key: value for key, value in
zip(self._ELEMENT_ATTRIBUTES,
dict_element[1:])})
if element_head['type'] == 'empty':
include_element = SubElement(current_element,
element_head.pop('tag'),
**element_head)
self._build_section(include_element,
dictionary[dict_element])
elif element_head['type'] == 'array':
include_element = SubElement(current_element,
element_head.pop('tag'),
**element_head)
for list_element in dictionary[dict_element]:
list_element_head = OrderedDict(
{key: value for key, value in
zip(self._VALUE_ATTRIBUTES,
list_element)}
)
SubElement(include_element,
list_element_head.pop('tag'),
**list_element_head)
else:
SubElement(current_element,
element_head.pop('tag'),
**element_head,
value=dictionary[dict_element])