- Преобразование XML в JSON и Dict в Python
- Преобразование XML в Dict и JSON
- Начало работы
- Установка модуля xmltodict
- XML в JSON
- Преобразование файла XML в JSON
- XML для Dict
- Поддержка пространств имен в XML
- Как преобразовать JSON в XML
- xmltodict
- Namespace support
- Streaming mode
- Roundtripping
- Ok, how do I get it?
- Using pypi
- RPM-based distro (Fedora, RHEL, …)
- Arch Linux
- Debian-based distro (Debian, Ubuntu, …)
- xmltodict
- Roundtripping
- Using pypi
Преобразование XML в JSON и Dict в Python
Сегодня мы узнаем, как преобразовать XML в JSON и XML в Dict в Python. Мы можем использовать модуль xmltodict в python для чтения файла XML и преобразования его в данные Dict или JSON.
Мы также можем передавать большие файлы XML и преобразовывать их в словарь. Прежде чем перейти к кодированию, давайте сначала разберемся, почему необходимо преобразование XML.
Преобразование XML в Dict и JSON
Файлы XML постепенно устаревают, но в сети есть довольно большие системы, которые все еще используют этот формат. XML тяжелее JSON, поэтому большинство разработчиков предпочитают последний в своих приложениях.
Когда приложениям необходимо понимать XML, предоставленный любым источником, преобразование его в JSON может оказаться утомительной задачей. Модуль xmltodict в Python делает эту задачу чрезвычайно простой и понятной для выполнения.
Начало работы
Мы можем начать работу с модулем xmltodict, но сначала нам нужно его установить. В основном мы будем использовать pip для выполнения установки.
Установка модуля xmltodict
Вот как мы можем установить модуль xmltodict с помощью индекса пакета (pip):
Это будет сделано быстро, поскольку xmltodict – очень легкий модуль. Вот результат этой установки:
Модуль не зависит от других внешних модулей, поэтому он легкий и позволяет избежать конфликтов версий.
Чтобы продемонстрировать, в системах на основе Debian этот модуль можно легко установить с помощью инструмента apt:
sudo apt install python-xmltodict
Еще один плюс в том, что у этого модуля есть официальный пакет Debian.
XML в JSON
Лучше всего начать работу этого модуля с выполнения операции, для которой он был предназначен в первую очередь, для преобразования XML в JSON. Давайте посмотрим на фрагмент кода, как это можно сделать:
import xmltodict import pprint import json my_xml = """""" pp = pprint.PrettyPrinter(indent=4) pp.pprint(json.dumps(xmltodict.parse(my_xml))) 123 Shubham
Здесь мы просто используем функцию parse(…) для преобразования данных XML в JSON, а затем мы используем модуль json для печати JSON в лучшем формате.
Преобразование файла XML в JSON
Хранение XML-данных в самом коде не всегда возможно и реально. Обычно мы храним наши данные либо в базе данных, либо в некоторых файлах. Мы можем напрямую выбирать файлы и конвертировать их в JSON. Давайте посмотрим на фрагмент кода, как мы можем выполнить преобразование с помощью файла XML:
import xmltodict import pprint import json with open('person.xml') as fd: doc = xmltodict.parse(fd.read()) pp = pprint.PrettyPrinter(indent=4) pp.pprint(json.dumps(doc))
Здесь мы использовали другой модуль pprint для печати вывода в отформатированном виде. Кроме того, использование функции open (…) необходимо, чтобы получить дескриптор File, а затем преобразовать файл в объект JSON.
XML для Dict
Как видно из названия модуля, xmltodict фактически преобразует предоставленные XML-данные в простой словарь. Итак, мы можем просто получить доступ к данным с помощью ключей словаря. Вот пример программы:
import xmltodict import pprint import json my_xml = """""" my_dict = xmltodict.parse(my_xml) print(my_dict['audience']['id']) print(my_dict['audience']['id']['@what']) 123 Shubham
Таким образом, теги могут использоваться как ключи вместе с ключами атрибутов. Ключи атрибутов просто должны иметь префикс @.
Поддержка пространств имен в XML
В данных XML у нас обычно есть набор пространств имен, который определяет объем данных, предоставляемых файлом XML. При преобразовании в формат JSON необходимо, чтобы эти пространства имен также сохранялись в формате JSON. Давайте рассмотрим этот пример XML-файла:
Вот пример программы о том, как мы можем включить пространства имен XML в формат JSON:
import xmltodict import pprint import json with open('person.xml') as fd: doc = xmltodict.parse(fd.read(), process_namespaces=True) pp = pprint.PrettyPrinter(indent=4) pp.pprint(json.dumps(doc))
Как преобразовать JSON в XML
Хотя преобразование из XML в JSON является основной целью этого модуля, xmltodict также поддерживает выполнение обратной операции, преобразовывая JSON в форму XML. Мы предоставим данные JSON в самой программе. Вот пример программы:
import xmltodict student = < "data" : < "name" : "Shubham", "marks" : < "math" : 92, "english" : 99 >, "id" : "s387hs3" > > print(xmltodict.unparse(student, pretty=True))
Обратите внимание, что для правильной работы необходимо указать один ключ JSON. Если учесть, что мы модифицируем нашу программу, чтобы она содержала несколько ключей JSON на самом первом уровне данных, например:
import xmltodict student = < "name" : "Shubham", "marks" : < "math" : 92, "english" : 99 >, "id" : "s387hs3" > print(xmltodict.unparse(student, pretty=True))
Это происходит потому, что xmltodict необходимо создать JSON с самым первым ключом в качестве корневого тега XML. Это означает, что на корневом уровне данных должен быть только один ключ JSON.
xmltodict
xmltodict is a Python module that makes working with XML feel like you are working with JSON, as in this «spec»:
>>> print(json.dumps(xmltodict.parse(""" . . . elements . more elements . . . element as well . . . """), indent=4)) < "mydocument": < "@has": "an attribute", "and": < "many": [ "elements", "more elements" ] >, "plus": < "@a": "complex", "#text": "element as well" >> >
Namespace support
By default, xmltodict does no XML namespace processing (it just treats namespace declarations as regular node attributes), but passing process_namespaces=True will make it expand namespaces for you:
>>> xml = """ . . 1 . 2 . 3 . . """ >>> xmltodict.parse(xml, process_namespaces=True) == < . 'http://defaultns.com/:root': < . 'http://defaultns.com/:x': '1', . 'http://a.com/:y': '2', . 'http://b.com/:z': '3', . >. > True
It also lets you collapse certain namespaces to shorthand prefixes, or skip them altogether:
>>> namespaces = < . 'http://defaultns.com/': None, # skip this namespace . 'http://a.com/': 'ns_a', # collapse "http://a.com/" ->"ns_a" . > >>> xmltodict.parse(xml, process_namespaces=True, namespaces=namespaces) == < . 'root': < . 'x': '1', . 'ns_a:y': '2', . 'http://b.com/:z': '3', . >, . > True
Streaming mode
xmltodict is very fast (Expat-based) and has a streaming mode with a small memory footprint, suitable for big XML dumps like Discogs or Wikipedia:
>>> def handle_artist(_, artist): . print(artist['name']) . return True >>> >>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'), . item_depth=2, item_callback=handle_artist) A Perfect Circle Fantômas King Crimson Chris Potter .
It can also be used from the command line to pipe objects to a script like this:
import sys, marshal while True: _, article = marshal.load(sys.stdin) print(article['title'])
$ cat enwiki-pages-articles.xml.bz2 | bunzip2 | xmltodict.py 2 | myscript.py AccessibleComputing Anarchism AfghanistanHistory AfghanistanGeography AfghanistanPeople AfghanistanCommunications Autism .
Or just cache the dicts so you don’t have to parse that big XML file again. You do this only once:
$ cat enwiki-pages-articles.xml.bz2 | bunzip2 | xmltodict.py 2 | gzip > enwiki.dicts.gz
And you reuse the dicts with every script that needs them:
$ cat enwiki.dicts.gz | gunzip | script1.py $ cat enwiki.dicts.gz | gunzip | script2.py .
Roundtripping
You can also convert in the other direction, using the unparse() method:
>>> mydict = < . 'response': < . 'status': 'good', . 'last_updated': '2014-02-16T23:10:12Z', . >. > >>> print(unparse(mydict, pretty=True)) good 2014-02-16T23:10:12Z
Text values for nodes can be specified with the cdata_key key in the python dict, while node properties can be specified with the attr_prefix prefixed to the key name in the python dict. The default value for attr_prefix is @ and the default value for cdata_key is #text .
>>> import xmltodict >>> >>> mydict = < . 'text': < . '@color':'red', . '@stroke':'2', . '#text':'This is a test' . >. > >>> print(xmltodict.unparse(mydict, pretty=True)) This is a test
Ok, how do I get it?
Using pypi
RPM-based distro (Fedora, RHEL, …)
$ sudo yum install python-xmltodict
Arch Linux
$ sudo pacman -S python-xmltodict
Debian-based distro (Debian, Ubuntu, …)
$ sudo apt install python-xmltodict
xmltodict
xmltodict is a Python module that makes working with XML feel like you are working with JSON, as in this «spec»:
By default, xmltodict does no XML namespace processing (it just treats namespace declarations as regular node attributes), but passing process_namespaces=True will make it expand namespaces for you:
1 2 3 It also lets you collapse certain namespaces to shorthand prefixes, or skip them altogether:
xmltodict is very fast (Expat-based) and has a streaming mode with a small memory footprint, suitable for big XML dumps like Discogs or Wikipedia:
It can also be used from the command line to pipe objects to a script like this:
Or just cache the dicts so you don't have to parse that big XML file again. You do this only once:
$ bunzip2 enwiki-pages-articles.xml.bz2 xmltodict.py gzip > enwiki.dicts.gz
And you reuse the dicts with every script that needs them:
$ gunzip enwiki.dicts.gz script1.py $ gunzip enwiki.dicts.gz script2.py .
Roundtripping
You can also convert in the other direction, using the unparse() method:
Text values for nodes can be specified with the cdata_key key in the python dict, while node properties can be specified with the attr_prefix prefixed to the key name in the python dict. The default value for attr_prefix is @ and the default value for cdata_key is #text .
Lists that are specified under a key in a dictionary use the key as a tag for each item. But if a list does have a parent key, for example if a list exists inside another list, it does not have a tag to use and the items are converted to a string as shown in the example below. To give tags to nested lists, use the expand_iter keyword argument to provide a tag as demonstrated below. Note that using expand_iter will break roundtripping.
Using pypi