README.md
1# xmltodict
2
3`xmltodict` is a Python module that makes working with XML feel like you are working with [JSON](http://docs.python.org/library/json.html), as in this ["spec"](http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html):
4
5[![Build Status](https://secure.travis-ci.org/martinblech/xmltodict.svg)](http://travis-ci.org/martinblech/xmltodict)
6
7```python
8>>> print(json.dumps(xmltodict.parse("""
9... <mydocument has="an attribute">
10... <and>
11... <many>elements</many>
12... <many>more elements</many>
13... </and>
14... <plus a="complex">
15... element as well
16... </plus>
17... </mydocument>
18... """), indent=4))
19{
20 "mydocument": {
21 "@has": "an attribute",
22 "and": {
23 "many": [
24 "elements",
25 "more elements"
26 ]
27 },
28 "plus": {
29 "@a": "complex",
30 "#text": "element as well"
31 }
32 }
33}
34```
35
36## Namespace support
37
38By 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:
39
40```python
41>>> xml = """
42... <root xmlns="http://defaultns.com/"
43... xmlns:a="http://a.com/"
44... xmlns:b="http://b.com/">
45... <x>1</x>
46... <a:y>2</a:y>
47... <b:z>3</b:z>
48... </root>
49... """
50>>> xmltodict.parse(xml, process_namespaces=True) == {
51... 'http://defaultns.com/:root': {
52... 'http://defaultns.com/:x': '1',
53... 'http://a.com/:y': '2',
54... 'http://b.com/:z': '3',
55... }
56... }
57True
58```
59
60It also lets you collapse certain namespaces to shorthand prefixes, or skip them altogether:
61
62```python
63>>> namespaces = {
64... 'http://defaultns.com/': None, # skip this namespace
65... 'http://a.com/': 'ns_a', # collapse "http://a.com/" -> "ns_a"
66... }
67>>> xmltodict.parse(xml, process_namespaces=True, namespaces=namespaces) == {
68... 'root': {
69... 'x': '1',
70... 'ns_a:y': '2',
71... 'http://b.com/:z': '3',
72... },
73... }
74True
75```
76
77## Streaming mode
78
79`xmltodict` is very fast ([Expat](http://docs.python.org/library/pyexpat.html)-based) and has a streaming mode with a small memory footprint, suitable for big XML dumps like [Discogs](http://discogs.com/data/) or [Wikipedia](http://dumps.wikimedia.org/):
80
81```python
82>>> def handle_artist(_, artist):
83... print(artist['name'])
84... return True
85>>>
86>>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'),
87... item_depth=2, item_callback=handle_artist)
88A Perfect Circle
89Fantômas
90King Crimson
91Chris Potter
92...
93```
94
95It can also be used from the command line to pipe objects to a script like this:
96
97```python
98import sys, marshal
99while True:
100 _, article = marshal.load(sys.stdin)
101 print(article['title'])
102```
103
104```sh
105$ bunzip2 enwiki-pages-articles.xml.bz2 | xmltodict.py 2 | myscript.py
106AccessibleComputing
107Anarchism
108AfghanistanHistory
109AfghanistanGeography
110AfghanistanPeople
111AfghanistanCommunications
112Autism
113...
114```
115
116Or just cache the dicts so you don't have to parse that big XML file again. You do this only once:
117
118```sh
119$ bunzip2 enwiki-pages-articles.xml.bz2 | xmltodict.py 2 | gzip > enwiki.dicts.gz
120```
121
122And you reuse the dicts with every script that needs them:
123
124```sh
125$ gunzip enwiki.dicts.gz | script1.py
126$ gunzip enwiki.dicts.gz | script2.py
127...
128```
129
130## Roundtripping
131
132You can also convert in the other direction, using the `unparse()` method:
133
134```python
135>>> mydict = {
136... 'response': {
137... 'status': 'good',
138... 'last_updated': '2014-02-16T23:10:12Z',
139... }
140... }
141>>> print(unparse(mydict, pretty=True))
142<?xml version="1.0" encoding="utf-8"?>
143<response>
144 <status>good</status>
145 <last_updated>2014-02-16T23:10:12Z</last_updated>
146</response>
147```
148
149Text 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`.
150
151```python
152>>> import xmltodict
153>>>
154>>> mydict = {
155... 'text': {
156... '@color':'red',
157... '@stroke':'2',
158... '#text':'This is a test'
159... }
160... }
161>>> print(xmltodict.unparse(mydict, pretty=True))
162<?xml version="1.0" encoding="utf-8"?>
163<text stroke="2" color="red">This is a test</text>
164```
165
166## Ok, how do I get it?
167
168### Using pypi
169
170You just need to
171
172```sh
173$ pip install xmltodict
174```
175
176### RPM-based distro (Fedora, RHEL, …)
177
178There is an [official Fedora package for xmltodict](https://apps.fedoraproject.org/packages/python-xmltodict).
179
180```sh
181$ sudo yum install python-xmltodict
182```
183
184### Arch Linux
185
186There is an [official Arch Linux package for xmltodict](https://www.archlinux.org/packages/community/any/python-xmltodict/).
187
188```sh
189$ sudo pacman -S python-xmltodict
190```
191
192### Debian-based distro (Debian, Ubuntu, …)
193
194There is an [official Debian package for xmltodict](https://tracker.debian.org/pkg/python-xmltodict).
195
196```sh
197$ sudo apt install python-xmltodict
198```
199
200### FreeBSD
201
202There is an [official FreeBSD port for xmltodict](https://svnweb.freebsd.org/ports/head/devel/py-xmltodict/).
203
204```sh
205$ pkg install py36-xmltodict
206```
207