diff --git a/src/tablib/formats/__init__.py b/src/tablib/formats/__init__.py
index 5162a866..f24b637a 100644
--- a/src/tablib/formats/__init__.py
+++ b/src/tablib/formats/__init__.py
@@ -11,6 +11,7 @@
from ._csv import CSVFormat
from ._json import JSONFormat
from ._tsv import TSVFormat
+from ._xml import XMLFormat
uninstalled_format_messages = {
"cli": {"package_name": "tabulate package", "extras_name": "cli"},
@@ -110,6 +111,7 @@ def register_builtins(self):
self.register('rst', 'tablib.formats._rst.ReSTFormat')
if find_spec('tabulate'):
self.register('cli', 'tablib.formats._cli.CLIFormat')
+ self.register('xml', XMLFormat())
def formats(self):
for key, frm in self._formats.items():
diff --git a/src/tablib/formats/_xml.py b/src/tablib/formats/_xml.py
new file mode 100644
index 00000000..5a93d239
--- /dev/null
+++ b/src/tablib/formats/_xml.py
@@ -0,0 +1,32 @@
+""" Tablib - XML support.
+"""
+
+import xml.etree.ElementTree as ET
+
+
+class XMLFormat:
+ title = 'xml'
+ extensions = ('xml',)
+
+ # TODO implement
+ # @classmethod
+ # def import_set(cls, dset, in_stream):
+ # dset.wipe()
+
+ @classmethod
+ def export_set(cls, dataset):
+ root = ET.Element('dataset')
+
+ for row_index, row in enumerate(dataset.dict):
+ row_node = ET.Element('row')
+ tags = dataset._data[row_index].tags
+ if tags:
+ row_node.set('tags', ','.join(tags))
+ for header, value in row.items():
+ value_node = ET.Element(header)
+ value_node.text = str(value)
+ row_node.append(value_node)
+
+ root.append(row_node)
+
+ return ET.tostring(root).decode()
diff --git a/tests/test_tablib.py b/tests/test_tablib.py
index ca57d00b..45467abf 100755
--- a/tests/test_tablib.py
+++ b/tests/test_tablib.py
@@ -1350,3 +1350,34 @@ def test_cli_export_grid(self):
'+---+---+---+\n| a | b | c |\n+---+---+---+',
tablib.Dataset(['a', 'b', 'c']).export('cli', tablefmt='grid')
)
+
+
+class XMLTests(BaseTestCase):
+ def test_xml_export(self):
+ """Verify exporting dataset object as XML."""
+
+ xml = ''
+ for row in self.founders:
+ xml += ''
+ for i, header in enumerate(self.founders.headers):
+ xml += '<{}>{}{}>'.format(header, row[i], header)
+ xml += '
'
+ xml += ''
+
+ self.assertEqual(xml, self.founders.xml)
+
+ def test_xml_export_row_with_tag(self):
+ """Verify exporting dataset with row tags object as XML."""
+
+ local_data = tablib.Dataset(headers=['A', 'B'])
+ local_data.append(('a', 'b'), tags=['tag 1', 'tag 2'])
+
+ xml = ''
+ for row_index, row in enumerate(local_data):
+ xml += ''.format(','.join(local_data._data[row_index].tags))
+ for header_index, header in enumerate(local_data.headers):
+ xml += '<{}>{}{}>'.format(header, row[header_index], header)
+ xml += '
'
+ xml += ''
+
+ self.assertEqual(xml, local_data.xml)