Skip to content

Commit ff1351a

Browse files
authored
item ommision (#76)
* item ommision * revert dicttoxml * add tests handle attr_type=True with item_wrap=False
1 parent 1c68713 commit ff1351a

File tree

5 files changed

+100
-27
lines changed

5 files changed

+100
-27
lines changed

README.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,37 @@ Outputs this:
9797
<avatar_url type="str">https://avatars0.githubusercontent.com/u/1?v=4</avatar_url>
9898
</all>
9999
100+
Omit List item
101+
--------------
102+
103+
By default, items in an array are wrapped in <item></item>. However, you can change this easily in your code like this:
104+
105+
.. code-block:: python
106+
107+
from json2xml import json2xml
108+
from json2xml.utils import readfromurl, readfromstring, readfromjson
109+
data = readfromstring(
110+
'{"my_items":[{"my_item":{"id":1} },{"my_item":{"id":2} }]}'
111+
)
112+
print(json2xml.Json2xml(data, item_wrap=False).to_xml())
113+
114+
115+
Outputs this:
116+
117+
.. code-block:: xml
118+
119+
<?xml version="1.0" ?>
120+
<all>
121+
<my_items type="list">
122+
<my_item>
123+
<id type="int">1</id>
124+
</my_item>
125+
<my_item>
126+
<id type="int">2</id>
127+
</my_item>
128+
</list>
129+
</all>
130+
100131
Optional Attribute Type Support
101132
-------------------------------
102133

json2xml/dicttoxml.py

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def default_item_func(parent):
134134
return "item"
135135

136136

137-
def convert(obj, ids, attr_type, item_func, cdata, parent="root"):
137+
def convert(obj, ids, attr_type, item_func, cdata, item_wrap, parent="root"):
138138
"""Routes the elements of an object to the right function to convert them
139139
based on their data type"""
140140

@@ -157,15 +157,15 @@ def convert(obj, ids, attr_type, item_func, cdata, parent="root"):
157157
return convert_none(item_name, "", attr_type, cdata)
158158

159159
if isinstance(obj, dict):
160-
return convert_dict(obj, ids, parent, attr_type, item_func, cdata)
160+
return convert_dict(obj, ids, parent, attr_type, item_func, cdata, item_wrap)
161161

162162
if isinstance(obj, collections.Iterable):
163-
return convert_list(obj, ids, parent, attr_type, item_func, cdata)
163+
return convert_list(obj, ids, parent, attr_type, item_func, cdata, item_wrap)
164164

165165
raise TypeError("Unsupported data type: %s (%s)" % (obj, type(obj).__name__))
166166

167167

168-
def convert_dict(obj, ids, parent, attr_type, item_func, cdata):
168+
def convert_dict(obj, ids, parent, attr_type, item_func, cdata, item_wrap):
169169
"""Converts a dict into an XML string."""
170170
LOG.info(
171171
'Inside convert_dict(): obj type is: "%s", obj="%s"'
@@ -201,7 +201,7 @@ def convert_dict(obj, ids, parent, attr_type, item_func, cdata):
201201
% (
202202
key,
203203
make_attrstring(attr),
204-
convert_dict(val, ids, key, attr_type, item_func, cdata),
204+
convert_dict(val, ids, key, attr_type, item_func, cdata, item_wrap),
205205
key,
206206
)
207207
)
@@ -214,7 +214,7 @@ def convert_dict(obj, ids, parent, attr_type, item_func, cdata):
214214
% (
215215
key,
216216
make_attrstring(attr),
217-
convert_list(val, ids, key, attr_type, item_func, cdata),
217+
convert_list(val, ids, key, attr_type, item_func, cdata, item_wrap),
218218
key,
219219
)
220220
)
@@ -230,7 +230,7 @@ def convert_dict(obj, ids, parent, attr_type, item_func, cdata):
230230
return "".join(output)
231231

232232

233-
def convert_list(items, ids, parent, attr_type, item_func, cdata):
233+
def convert_list(items, ids, parent, attr_type, item_func, cdata, item_wrap):
234234
"""Converts a list into an XML string."""
235235
LOG.info("Inside convert_list()")
236236
output = []
@@ -258,23 +258,39 @@ def convert_list(items, ids, parent, attr_type, item_func, cdata):
258258

259259
elif isinstance(item, dict):
260260
if not attr_type:
261-
addline(
262-
"<%s>%s</%s>"
263-
% (
264-
item_name,
265-
convert_dict(item, ids, parent, attr_type, item_func, cdata),
266-
item_name,
261+
if (item_wrap):
262+
addline(
263+
"<%s>%s</%s>"
264+
% (
265+
item_name,
266+
convert_dict(item, ids, parent, attr_type, item_func, cdata, item_wrap),
267+
item_name,
268+
)
269+
)
270+
else:
271+
addline(
272+
"%s"
273+
% (
274+
convert_dict(item, ids, parent, attr_type, item_func, cdata, item_wrap),
275+
)
267276
)
268-
)
269277
else:
270-
addline(
271-
'<%s type="dict">%s</%s>'
272-
% (
273-
item_name,
274-
convert_dict(item, ids, parent, attr_type, item_func, cdata),
275-
item_name,
278+
if (item_wrap):
279+
addline(
280+
'<%s type="dict">%s</%s>'
281+
% (
282+
item_name,
283+
convert_dict(item, ids, parent, attr_type, item_func, cdata, item_wrap),
284+
item_name,
285+
)
286+
)
287+
else:
288+
addline(
289+
'%s'
290+
% (
291+
convert_dict(item, ids, parent, attr_type, item_func, cdata, item_wrap),
292+
)
276293
)
277-
)
278294

279295
elif isinstance(item, collections.Iterable):
280296
if not attr_type:
@@ -283,7 +299,7 @@ def convert_list(items, ids, parent, attr_type, item_func, cdata):
283299
% (
284300
item_name,
285301
make_attrstring(attr),
286-
convert_list(item, ids, item_name, attr_type, item_func, cdata),
302+
convert_list(item, ids, item_name, attr_type, item_func, cdata, item_wrap),
287303
item_name,
288304
)
289305
)
@@ -293,7 +309,7 @@ def convert_list(items, ids, parent, attr_type, item_func, cdata):
293309
% (
294310
item_name,
295311
make_attrstring(attr),
296-
convert_list(item, ids, item_name, attr_type, item_func, cdata),
312+
convert_list(item, ids, item_name, attr_type, item_func, cdata, item_wrap),
297313
item_name,
298314
)
299315
)
@@ -361,6 +377,7 @@ def dicttoxml(
361377
custom_root="root",
362378
ids=False,
363379
attr_type=True,
380+
item_wrap=True,
364381
item_func=default_item_func,
365382
cdata=False,
366383
):
@@ -377,6 +394,8 @@ def dicttoxml(
377394
- item_func specifies what function should generate the element name for
378395
items in a list.
379396
Default is 'item'
397+
- item_wrap specifies whether to nest items in array in <item/>
398+
Default is True
380399
- cdata specifies whether string values should be wrapped in CDATA sections.
381400
Default is False
382401
"""
@@ -387,6 +406,6 @@ def dicttoxml(
387406
output = []
388407
output.append('<?xml version="1.0" encoding="UTF-8" ?>')
389408
output.append(
390-
f"<{custom_root}>{convert(obj, ids, attr_type, item_func, cdata, parent=custom_root)}</{custom_root}>"
409+
f"<{custom_root}>{convert(obj, ids, attr_type, item_func, cdata, item_wrap, parent=custom_root)}</{custom_root}>"
391410
)
392411
return "".join(output).encode("utf-8")

json2xml/json2xml.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ def __init__(
1010
wrapper: str = "all",
1111
root: bool = True,
1212
pretty: bool = True,
13-
attr_type: bool = True
13+
attr_type: bool = True,
14+
item_wrap: bool = True
1415
):
1516
self.data = data
1617
self.pretty = pretty
1718
self.wrapper = wrapper
1819
self.attr_type = attr_type
1920
self.root = root
21+
self.item_wrap = item_wrap
2022

2123
def to_xml(self) -> Optional[Any]:
2224
"""
@@ -27,7 +29,8 @@ def to_xml(self) -> Optional[Any]:
2729
self.data,
2830
root=self.root,
2931
custom_root=self.wrapper,
30-
attr_type=self.attr_type
32+
attr_type=self.attr_type,
33+
item_wrap=self.item_wrap
3134
)
3235
if self.pretty:
3336
return parseString(xml_data).toprettyxml()

json2xml/utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class StringReadError(Exception):
1616
pass
1717

1818

19-
2019
def readfromjson(filename: str) -> Dict[str, str]:
2120
"""
2221
Reads a json string and emits json string

tests/test_json2xml.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,24 @@ def test_no_wrapper_and_indent(self):
8989
assert "test" in old_dict.keys()
9090
# reverse test, say a wrapper called ramdom won't be present
9191
assert "random" not in old_dict.keys()
92+
93+
def test_item_wrap(self):
94+
data = readfromstring(
95+
'{"my_items":[{"my_item":{"id":1} },{"my_item":{"id":2} }]}'
96+
)
97+
xmldata = json2xml.Json2xml(data, root=False, pretty=False).to_xml()
98+
old_dict = xmltodict.parse(xmldata)
99+
# item must be present within my_items
100+
assert "item" in old_dict['all']['my_items']
101+
102+
xmldata = json2xml.Json2xml(data, root=False, pretty=False, item_wrap=False, attr_type=False).to_xml()
103+
old_dict = xmltodict.parse(xmldata)
104+
# my_item must be present within my_items
105+
assert "my_item" in old_dict['all']['my_items']
106+
107+
xmldata = json2xml.Json2xml(data, root=False, pretty=False, item_wrap=False).to_xml()
108+
print(xmldata)
109+
old_dict = xmltodict.parse(xmldata)
110+
# my_item must be present within my_items
111+
print(old_dict['all']['my_items'])
112+
assert "my_item" in old_dict['all']['my_items']

0 commit comments

Comments
 (0)