Шаг 105.
Python: сборник рецептов.
Кодирование и обработка данных. Преобразование словарей в XML

    На этом шаге мы продолжим знакомиться с возможностями модуля xml.etree.ElementTree.

Задача

    Вы хотите взять данные из словаря Python и превратить их в XML.

Решение

    Хотя библиотека xml.etree.ElementTree обычно используется для парсинга, ее также можно применить для создания XML-документов. Например, посмотрите на такую функцию:

>>> from xml.etree.ElementTree import Element
>>> def dict_to_xml(tag, d):
	'''
         Превращает простой словарь пар ключ/значение в XML
        '''
	elem = Element(tag)
	for key, val in d.items():
		child = Element(key)
		child.text = str(val)
		elem.append(child)
	return elem

    Вот пример ее работы:

>>> s = {'name': 'GOOG', 'shares': 100, 'price': 490.1}
>>> e = dict_to_xml('stock', s)
>>> e
<Element 'stock' at 0x0000028823F9B360>
>>> 

    Результатом этого преобразования является экземпляр Element. Для ввода-вывода его можно легко конвертировать в байтовую строку - для этого нужно использовать функцию tostring() из модуля xml.etree.ElementTree. Например:

>>> from xml.etree.ElementTree import tostring
>>> tostring(e)
b'<stock><name>GOOG</name><shares>100</shares><price>490.1</price></stock>'
>>> 

    Если вы хотите прикрепить атрибуты к элементу, используйте метод set():

>>> e.set('_id', '1234')
>>> tostring(e)
b'<stock _id="1234"><name>GOOG</name><shares>100</shares><price>490.1</price></stock>'
>>>

    Если порядок элементов имеет значение, подумайте над созданием OrderedDict вместо обычного словаря.

Обсуждение

    При генерации XML вы можете склоняться к простому созданию строк. Например:

>>> def dict_to_xml_str(tag, d):
	'''
        Превращает простой словарь пар ключ/значение в XML
        '''
	parts = ['<{}>'.format(tag)]
	for key, val in d.items():
		parts.append('<{0}>{1}</{0}>'.format(key,val))
		parts.append('</{}>'.format(tag))
	return ''.join(parts)

    Проблема в том, что вы влезете в большие неприятности, если попытаетесь сделать это вручную. Например, что случится, если значения словаря будут содержать спецсимволы?

>>> d = {'name': '<spam>'}
>>> # Создание строки
>>> dict_to_xml_str('item', d)
'<item><name><spam></name></item>'
>>> # Правильное создание XML
>>> e = dict_to_xml('item', d)
>>> tostring(e)
b'<item><name>&lt;spam&gt;</name></item>'
>>> 

    Обратите внимание, как в последнем примере символы <and> заменяются на &lt;and&gt;.

    Для справки: если вам когда-либо потребуется вручную экранировать или деэкранировать такие символы, вы можете использовать функции escape() и unescape() из модуля xml.sax.saxutils. Например:

>>> from xml.sax.saxutils import escape, unescape
>>> escape('<spam>')
'&lt;spam&gt;'
>>> unescape(_)
'<spam>'
>>>

    Если оставить в стороне создание правильного вывода, другая причина создавать экземпляры Element вместо строк заключается в том, что их легче объединять друг с другом для создания более крупного документа. Получающиеся экземпляры Element также могут быть обработаны различными способами без необходимости парсить XML-текст. Вы можете провести всю обработку данных высокоуровневым способом, а затем в самом конце вывести их в строковой форме.

    На следующем шаге мы рассмотрим парсинг, изменение и перезапись XML.




Предыдущий шаг Содержание Следующий шаг