# coding: utf-8
import json
import xml.dom.minidom as md
import json
def cheng(s):
inp = json.loads(s)
return dict2xml(inp, True)
def dict2xml(structure,tostring=False):
assert len(structure) == 1, 'Structure must have only one root element'
assert isinstance(structure,Mapping), 'Structure must be a mapping object such as dict'
root_element_name, value = next(structure.iteritems())
impl = minidom.getDOMImplementation()
doc = impl.createDocument(None,str(root_element_name),None)
dict2element(doc.documentElement,value,doc)
return doc.toxml() if tostring else doc
def load_xml(xml):
u"""
Функция извлечения данных из XML-строки, содержащей JSON-данные
"""
try:
doc = md.parseString(xml)
except TypeError:
raise AssertionError(
u'XML-документ должен быть строкой!')
except:
raise AssertionError(u'Невалидный XML!')
top = doc.firstChild
assert top.tagName == u'JSON', (
u'Тэг верхнего уровня должен иметь имя "JSON"')
assert len(top.childNodes) == 1, (
u'JSON не может быть пустым!')
def wrong_tag(el, parser):
raise AssertionError(u'Недопустимый тэг: "%s"!' % el.tagName)
def item_in_wrong_place(el, parser):
raise AssertionError(u'Неожиданное появление тэга "ITEM"!')
# парсеры отдельных элементов
parse_integer = lambda el, parser: int(el.firstChild.wholeText)
parse_float = lambda el, parser: float(el.firstChild.wholeText)
parse_string = lambda el, parser: el.firstChild.wholeText
parse_null = lambda el, parser: None
def parse_list(el, parser):
result = []
for subel in el.childNodes:
result.append(parser(subel))
return result
def parse_dict(el, parser):
result = {}
for subel in el.childNodes:
if subel.tagName != u'ITEM':
raise AssertionError(
u'Элементами тэга "DICT" могут быть только тэги "ITEM"!')
assert subel.hasAttribute('name'), (
u'Тэг "ITEM" должен иметь атрибут "name"!')
assert len(subel.childNodes) == 1, (
u'Тэг "ITEM" должен ровно один дочерный элемент!')
result[subel.getAttribute('name')] = parser(subel.firstChild)
return result
# парсер - точка входа
def parse(el):
fn = {
u'INTEGER': parse_integer,
u'FLOAT': parse_float,
u'STRING': parse_string,
u'LIST': parse_list,
u'DICT': parse_dict,
u'NULL': parse_null,
u'ITEM': item_in_wrong_place,
}.get(el.tagName, wrong_tag)
try:
return fn(el, parse)
except (TypeError, ValueError):
raise AssertionError(u'Неверный формат тэга "%s"!' % el.tagName)
return parse(top.firstChild)
src = [
{'type': u'human', 'name': u'Vasiliy Pupkin', 'age': 12},
{'type': u'pet', 'name': u'Spot',
'bread': u'hound', 'weight': 1.5, 'owner': None},
{'type': u'pet', 'name': u'Leo', 'owners': [
{'name': u'Masha'},
{'name': u'Kolya', 'parents': {'mother': u'Maria', 'father': u'Ivan'}},
]},
]
ch = lambda data: cheng(json.dumps(data))
try:
assert load_xml(ch(None)) == None, (
u'Неверно преобразуется None!')
assert load_xml(ch(u"123")) == u"123", (
u'Неверно преобразуются строки!')
assert load_xml(ch(777)) == 777, (
u'Неверно преобразуются целые числа!')
assert load_xml(ch(77.7)) == 77.7, (
u'Неверно преобразуются числа с плавающей точкой!')
assert load_xml(ch([1, 2, 3])) == [1, 2, 3], (
u'Неверно преобразуются списки!')
assert load_xml(ch({'a': u'b'})) == {'a': u'b'}, (
u'Неверно преобразуются словари!')
assert load_xml(ch(src)) == src, (
u'Неверно обрабатываются комплексные данные!')
except AssertionError as msg:
print '>>>', unicode(msg).encode('utf-8')
IyBjb2Rpbmc6IHV0Zi04CgppbXBvcnQganNvbgppbXBvcnQgeG1sLmRvbS5taW5pZG9tIGFzIG1kCgoKCmltcG9ydCBqc29uCgpkZWYgY2hlbmcocyk6CglpbnAgPSBqc29uLmxvYWRzKHMpCglyZXR1cm4gZGljdDJ4bWwoaW5wLCBUcnVlKQogIApkZWYgZGljdDJ4bWwoc3RydWN0dXJlLHRvc3RyaW5nPUZhbHNlKToKCiAgICBhc3NlcnQgbGVuKHN0cnVjdHVyZSkgPT0gMSwgJ1N0cnVjdHVyZSBtdXN0IGhhdmUgb25seSBvbmUgcm9vdCBlbGVtZW50JwogICAgYXNzZXJ0IGlzaW5zdGFuY2Uoc3RydWN0dXJlLE1hcHBpbmcpLCAnU3RydWN0dXJlIG11c3QgYmUgYSBtYXBwaW5nIG9iamVjdCBzdWNoIGFzIGRpY3QnCgogICAgcm9vdF9lbGVtZW50X25hbWUsIHZhbHVlID0gbmV4dChzdHJ1Y3R1cmUuaXRlcml0ZW1zKCkpCiAgICBpbXBsID0gbWluaWRvbS5nZXRET01JbXBsZW1lbnRhdGlvbigpCiAgICBkb2MgPSBpbXBsLmNyZWF0ZURvY3VtZW50KE5vbmUsc3RyKHJvb3RfZWxlbWVudF9uYW1lKSxOb25lKQogICAgZGljdDJlbGVtZW50KGRvYy5kb2N1bWVudEVsZW1lbnQsdmFsdWUsZG9jKQogICAgcmV0dXJuIGRvYy50b3htbCgpIGlmIHRvc3RyaW5nIGVsc2UgZG9jIAoKCgpkZWYgbG9hZF94bWwoeG1sKToKICAgIHUiIiIKICAgINCk0YPQvdC60YbQuNGPINC40LfQstC70LXRh9C10L3QuNGPINC00LDQvdC90YvRhSDQuNC3IFhNTC3RgdGC0YDQvtC60LgsINGB0L7QtNC10YDQttCw0YnQtdC5IEpTT04t0LTQsNC90L3Ri9C1CiAgICAiIiIKICAgIHRyeToKICAgICAgICBkb2MgPSBtZC5wYXJzZVN0cmluZyh4bWwpCiAgICBleGNlcHQgVHlwZUVycm9yOgogICAgICAgIHJhaXNlIEFzc2VydGlvbkVycm9yKAogICAgICAgICAgICB1J1hNTC3QtNC+0LrRg9C80LXQvdGCINC00L7Qu9C20LXQvSDQsdGL0YLRjCDRgdGC0YDQvtC60L7QuSEnKQogICAgZXhjZXB0OgogICAgICAgIHJhaXNlIEFzc2VydGlvbkVycm9yKHUn0J3QtdCy0LDQu9C40LTQvdGL0LkgWE1MIScpCgogICAgdG9wID0gZG9jLmZpcnN0Q2hpbGQKICAgIGFzc2VydCB0b3AudGFnTmFtZSA9PSB1J0pTT04nLCAoCiAgICAgICAgdSfQotGN0LMg0LLQtdGA0YXQvdC10LPQviDRg9GA0L7QstC90Y8g0LTQvtC70LbQtdC9INC40LzQtdGC0Ywg0LjQvNGPICJKU09OIicpCiAgICBhc3NlcnQgbGVuKHRvcC5jaGlsZE5vZGVzKSA9PSAxLCAoCiAgICAgICAgdSdKU09OINC90LUg0LzQvtC20LXRgiDQsdGL0YLRjCDQv9GD0YHRgtGL0LwhJykKCiAgICBkZWYgd3JvbmdfdGFnKGVsLCBwYXJzZXIpOgogICAgICAgIHJhaXNlIEFzc2VydGlvbkVycm9yKHUn0J3QtdC00L7Qv9GD0YHRgtC40LzRi9C5INGC0Y3QszogIiVzIiEnICUgZWwudGFnTmFtZSkKCiAgICBkZWYgaXRlbV9pbl93cm9uZ19wbGFjZShlbCwgcGFyc2VyKToKICAgICAgICByYWlzZSBBc3NlcnRpb25FcnJvcih1J9Cd0LXQvtC20LjQtNCw0L3QvdC+0LUg0L/QvtGP0LLQu9C10L3QuNC1INGC0Y3Qs9CwICJJVEVNIiEnKQoKICAgICMg0L/QsNGA0YHQtdGA0Ysg0L7RgtC00LXQu9GM0L3Ri9GFINGN0LvQtdC80LXQvdGC0L7QsgogICAgcGFyc2VfaW50ZWdlciA9IGxhbWJkYSBlbCwgcGFyc2VyOiBpbnQoZWwuZmlyc3RDaGlsZC53aG9sZVRleHQpCiAgICBwYXJzZV9mbG9hdCA9IGxhbWJkYSBlbCwgcGFyc2VyOiBmbG9hdChlbC5maXJzdENoaWxkLndob2xlVGV4dCkKICAgIHBhcnNlX3N0cmluZyA9IGxhbWJkYSBlbCwgcGFyc2VyOiBlbC5maXJzdENoaWxkLndob2xlVGV4dAogICAgcGFyc2VfbnVsbCA9IGxhbWJkYSBlbCwgcGFyc2VyOiBOb25lCgogICAgZGVmIHBhcnNlX2xpc3QoZWwsIHBhcnNlcik6CiAgICAgICAgcmVzdWx0ID0gW10KICAgICAgICBmb3Igc3ViZWwgaW4gZWwuY2hpbGROb2RlczoKICAgICAgICAgICAgcmVzdWx0LmFwcGVuZChwYXJzZXIoc3ViZWwpKQogICAgICAgIHJldHVybiByZXN1bHQKCiAgICBkZWYgcGFyc2VfZGljdChlbCwgcGFyc2VyKToKICAgICAgICByZXN1bHQgPSB7fQogICAgICAgIGZvciBzdWJlbCBpbiBlbC5jaGlsZE5vZGVzOgogICAgICAgICAgICBpZiBzdWJlbC50YWdOYW1lICE9IHUnSVRFTSc6CiAgICAgICAgICAgICAgICByYWlzZSBBc3NlcnRpb25FcnJvcigKICAgICAgICAgICAgICAgICAgIHUn0K3Qu9C10LzQtdC90YLQsNC80Lgg0YLRjdCz0LAgIkRJQ1QiINC80L7Qs9GD0YIg0LHRi9GC0Ywg0YLQvtC70YzQutC+INGC0Y3Qs9C4ICJJVEVNIiEnKQogICAgICAgICAgICBhc3NlcnQgc3ViZWwuaGFzQXR0cmlidXRlKCduYW1lJyksICgKICAgICAgICAgICAgICAgIHUn0KLRjdCzICJJVEVNIiDQtNC+0LvQttC10L0g0LjQvNC10YLRjCDQsNGC0YDQuNCx0YPRgiAibmFtZSIhJykKICAgICAgICAgICAgYXNzZXJ0IGxlbihzdWJlbC5jaGlsZE5vZGVzKSA9PSAxLCAoCiAgICAgICAgICAgICAgICB1J9Ci0Y3QsyAiSVRFTSIg0LTQvtC70LbQtdC9INGA0L7QstC90L4g0L7QtNC40L0g0LTQvtGH0LXRgNC90YvQuSDRjdC70LXQvNC10L3RgiEnKQogICAgICAgICAgICByZXN1bHRbc3ViZWwuZ2V0QXR0cmlidXRlKCduYW1lJyldID0gcGFyc2VyKHN1YmVsLmZpcnN0Q2hpbGQpCiAgICAgICAgcmV0dXJuIHJlc3VsdAoKICAgICMg0L/QsNGA0YHQtdGAIC0g0YLQvtGH0LrQsCDQstGF0L7QtNCwCiAgICBkZWYgcGFyc2UoZWwpOgogICAgICAgIGZuID0gewogICAgICAgICAgICB1J0lOVEVHRVInOiBwYXJzZV9pbnRlZ2VyLAogICAgICAgICAgICB1J0ZMT0FUJzogcGFyc2VfZmxvYXQsCiAgICAgICAgICAgIHUnU1RSSU5HJzogcGFyc2Vfc3RyaW5nLAogICAgICAgICAgICB1J0xJU1QnOiBwYXJzZV9saXN0LAogICAgICAgICAgICB1J0RJQ1QnOiBwYXJzZV9kaWN0LAogICAgICAgICAgICB1J05VTEwnOiBwYXJzZV9udWxsLAogICAgICAgICAgICB1J0lURU0nOiBpdGVtX2luX3dyb25nX3BsYWNlLAogICAgICAgIH0uZ2V0KGVsLnRhZ05hbWUsIHdyb25nX3RhZykKICAgICAgICB0cnk6CiAgICAgICAgICAgIHJldHVybiBmbihlbCwgcGFyc2UpCiAgICAgICAgZXhjZXB0IChUeXBlRXJyb3IsIFZhbHVlRXJyb3IpOgogICAgICAgICAgICByYWlzZSBBc3NlcnRpb25FcnJvcih1J9Cd0LXQstC10YDQvdGL0Lkg0YTQvtGA0LzQsNGCINGC0Y3Qs9CwICIlcyIhJyAlIGVsLnRhZ05hbWUpCgogICAgcmV0dXJuIHBhcnNlKHRvcC5maXJzdENoaWxkKQoKCnNyYyA9IFsKICAgIHsndHlwZSc6IHUnaHVtYW4nLCAnbmFtZSc6IHUnVmFzaWxpeSBQdXBraW4nLCAnYWdlJzogMTJ9LAogICAgeyd0eXBlJzogdSdwZXQnLCAnbmFtZSc6IHUnU3BvdCcsCiAgICAgICAgJ2JyZWFkJzogdSdob3VuZCcsICd3ZWlnaHQnOiAxLjUsICdvd25lcic6IE5vbmV9LAogICAgeyd0eXBlJzogdSdwZXQnLCAnbmFtZSc6IHUnTGVvJywgJ293bmVycyc6IFsKICAgICAgICB7J25hbWUnOiB1J01hc2hhJ30sCiAgICAgICAgeyduYW1lJzogdSdLb2x5YScsICdwYXJlbnRzJzogeydtb3RoZXInOiB1J01hcmlhJywgJ2ZhdGhlcic6IHUnSXZhbid9fSwKICAgIF19LApdCgoKY2ggPSBsYW1iZGEgZGF0YTogY2hlbmcoanNvbi5kdW1wcyhkYXRhKSkKdHJ5OgogICAgYXNzZXJ0IGxvYWRfeG1sKGNoKE5vbmUpKSA9PSBOb25lLCAoCiAgICAgICAgdSfQndC10LLQtdGA0L3QviDQv9GA0LXQvtCx0YDQsNC30YPQtdGC0YHRjyBOb25lIScpCgogICAgYXNzZXJ0IGxvYWRfeG1sKGNoKHUiMTIzIikpID09IHUiMTIzIiwgKAogICAgICAgIHUn0J3QtdCy0LXRgNC90L4g0L/RgNC10L7QsdGA0LDQt9GD0Y7RgtGB0Y8g0YHRgtGA0L7QutC4IScpCgogICAgYXNzZXJ0IGxvYWRfeG1sKGNoKDc3NykpID09IDc3NywgKAogICAgICAgIHUn0J3QtdCy0LXRgNC90L4g0L/RgNC10L7QsdGA0LDQt9GD0Y7RgtGB0Y8g0YbQtdC70YvQtSDRh9C40YHQu9CwIScpCgogICAgYXNzZXJ0IGxvYWRfeG1sKGNoKDc3LjcpKSA9PSA3Ny43LCAoCiAgICAgICAgdSfQndC10LLQtdGA0L3QviDQv9GA0LXQvtCx0YDQsNC30YPRjtGC0YHRjyDRh9C40YHQu9CwINGBINC/0LvQsNCy0LDRjtGJ0LXQuSDRgtC+0YfQutC+0LkhJykKCiAgICBhc3NlcnQgbG9hZF94bWwoY2goWzEsIDIsIDNdKSkgPT0gWzEsIDIsIDNdLCAoCiAgICAgICAgdSfQndC10LLQtdGA0L3QviDQv9GA0LXQvtCx0YDQsNC30YPRjtGC0YHRjyDRgdC/0LjRgdC60LghJykKCiAgICBhc3NlcnQgbG9hZF94bWwoY2goeydhJzogdSdiJ30pKSA9PSB7J2EnOiB1J2InfSwgKAogICAgICAgIHUn0J3QtdCy0LXRgNC90L4g0L/RgNC10L7QsdGA0LDQt9GD0Y7RgtGB0Y8g0YHQu9C+0LLQsNGA0LghJykKCiAgICBhc3NlcnQgbG9hZF94bWwoY2goc3JjKSkgPT0gc3JjLCAoCiAgICAgICAgdSfQndC10LLQtdGA0L3QviDQvtCx0YDQsNCx0LDRgtGL0LLQsNGO0YLRgdGPINC60L7QvNC/0LvQtdC60YHQvdGL0LUg0LTQsNC90L3Ri9C1IScpCgpleGNlcHQgQXNzZXJ0aW9uRXJyb3IgYXMgbXNnOgogICAgcHJpbnQgJz4+PicsIHVuaWNvZGUobXNnKS5lbmNvZGUoJ3V0Zi04JykK