Skip to content

Commit e83b063

Browse files
committed
fix(json2xml): works exactly as needed.
Producing non-malformed pretty xml
1 parent e0724fb commit e83b063

1 file changed

Lines changed: 53 additions & 32 deletions

File tree

etc/json2xml.py

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -126,35 +126,48 @@ def internal_to_elem(pfsh, factory=ET.Element):
126126
sublist = []
127127
tags = list(pfsh.keys())
128128

129-
# Allow deeply nested structures
130-
for tag in tags:
131-
value = pfsh[tag]
132-
# we santize values automatically
133-
# $ref -> _ref
134-
if tag.startswith('$'):
135-
tag = '_' + tag[1:]
136-
137-
if isinstance(value, dict):
138-
for k, v in value.items():
139-
if k[:1] == "@":
140-
attribs[k[1:]] = v
141-
elif k == "#text":
142-
text = v
143-
elif k == "#tail":
144-
tail = v
145-
elif isinstance(v, list):
146-
for v2 in v:
147-
sublist.append(internal_to_elem({k: v2}, factory=factory))
148-
else:
149-
sublist.append(internal_to_elem({k: v}, factory=factory))
150-
else:
151-
text = value
152-
e = factory(tag, attribs)
129+
if len(tags) > 1:
130+
raise ValueError("Illegal structure with multiple tags: %s" % tag)
131+
132+
tag = tags[0]
133+
value = pfsh[tag]
134+
135+
def sani_value(v):
136+
if v is None:
137+
return v
138+
return unicode(v)
139+
140+
# we santize values automatically
141+
# $ref -> _ref
142+
if tag.startswith('$'):
143+
tag = '_' + tag[1:]
144+
if ':' in tag:
145+
assert isinstance(value, dict), "hardcoded requirement: value must be dict for us to sanitize tag"
146+
tk = 'value'
147+
assert tk not in value
148+
value[tk] = tag
149+
tag = 'item'
150+
if isinstance(value, dict):
151+
for k, v in value.items():
152+
if k[:1] == "@":
153+
attribs[k[1:]] = v
154+
elif k == "#text":
155+
text = v
156+
elif k == "#tail":
157+
tail = v
158+
elif isinstance(v, list):
159+
for v2 in v:
160+
sublist.append(internal_to_elem({k: v2}, factory=factory))
161+
else:
162+
sublist.append(internal_to_elem({k: v}, factory=factory))
163+
else:
164+
text = value
165+
e = factory(tag, attribs)
153166

154167
for sub in sublist:
155168
e.append(sub)
156-
e.text = unicode(text)
157-
e.tail = unicode(tail)
169+
e.text = sani_value(text)
170+
e.tail = sani_value(tail)
158171
return e
159172

160173

@@ -191,7 +204,7 @@ def xml2json(xmlstring, options, strip_ns=1, strip=1):
191204
return elem2json(elem, options, strip_ns=strip_ns, strip=strip)
192205

193206

194-
def json2xml(json_data, factory=ET.Element):
207+
def json2xml(json_data, options, factory=ET.Element):
195208

196209
"""Convert a JSON string into an XML string.
197210
@@ -202,8 +215,16 @@ def json2xml(json_data, factory=ET.Element):
202215
if not isinstance(json_data, dict):
203216
json_data = json.loads(json_data)
204217

218+
if len(json_data.keys()) > 1:
219+
json_data = dict(root = json_data)
220+
205221
elem = internal_to_elem(json_data, factory)
206-
return minidom.parseString(ET.tostring(elem)).toprettyxml(indent='\t')
222+
223+
xml_str = ET.tostring(elem)
224+
225+
if options.pretty:
226+
xml_str = minidom.parseString(xml_str).toprettyxml(indent='\t')
227+
return xml_str
207228

208229

209230
def main():
@@ -219,7 +240,7 @@ def main():
219240
dest="strip_text", help="Strip text for xml2json")
220241
p.add_option(
221242
'--pretty', action="store_true",
222-
dest="pretty", help="Format JSON output so it is easier to read")
243+
dest="pretty", help="Format JSON/HTML output so it is easier to read")
223244
p.add_option(
224245
'--strip_namespace', action="store_true",
225246
dest="strip_ns", help="Strip namespace for xml2json")
@@ -250,14 +271,14 @@ def main():
250271
if (options.type == "xml2json"):
251272
out = xml2json(input, options, strip_ns, strip)
252273
else:
253-
out = json2xml(input)
274+
out = json2xml(input, options)
254275

255276
if (options.out):
256-
file = open(options.out, 'w')
277+
file = open(options.out, 'wb')
257278
file.write(out)
258279
file.close()
259280
else:
260-
print(out)
281+
print(out.encode('utf-8'))
261282

262283
if __name__ == "__main__":
263284
main()

0 commit comments

Comments
 (0)