xml.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. from xml.etree import ElementTree
  2. from darabonba.model import DaraModel
  3. from collections import defaultdict
  4. class XML:
  5. _LIST_TYPE = (list, tuple, set)
  6. @staticmethod
  7. def __get_xml_factory(elem, val, parent_element=None):
  8. if val is None:
  9. return
  10. if isinstance(val, dict):
  11. XML.__get_xml_by_dict(elem, val)
  12. elif isinstance(val, XML._LIST_TYPE):
  13. if parent_element is None:
  14. raise RuntimeError("Missing root tag")
  15. XML.__get_xml_by_list(elem, val, parent_element)
  16. else:
  17. elem.text = str(val)
  18. @staticmethod
  19. def __get_xml_by_dict(elem, val):
  20. for k in val:
  21. sub_elem = ElementTree.SubElement(elem, k)
  22. XML.__get_xml_factory(sub_elem, val[k], elem)
  23. @staticmethod
  24. def __get_xml_by_list(elem, val, parent_element):
  25. i = 0
  26. tag_name = elem.tag
  27. if val.__len__() > 0:
  28. XML.__get_xml_factory(elem, val[0], parent_element)
  29. for item in val:
  30. if i > 0:
  31. sub_elem = ElementTree.SubElement(parent_element, tag_name)
  32. XML.__get_xml_factory(sub_elem, item, parent_element)
  33. i = i + 1
  34. @staticmethod
  35. def _parse_xml(t):
  36. d = {t.tag: {} if t.attrib else None}
  37. children = list(t)
  38. if children:
  39. dd = defaultdict(list)
  40. for dc in map(XML._parse_xml, children):
  41. for k, v in dc.items():
  42. dd[k].append(v)
  43. d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
  44. if t.attrib:
  45. d[t.tag].update(('@' + k, v) for k, v in t.attrib.items())
  46. if t.text:
  47. text = t.text.strip()
  48. if children or t.attrib:
  49. if text:
  50. d[t.tag]['#text'] = text
  51. else:
  52. d[t.tag] = text
  53. return d
  54. @staticmethod
  55. def parse_xml(body, response=None):
  56. """
  57. Parse body into the response, and put the resposne into a object
  58. @param body: source content
  59. @param response: target model
  60. @return the final object
  61. """
  62. return XML._parse_xml(ElementTree.fromstring(body))
  63. @staticmethod
  64. def to_xml(body):
  65. """
  66. Parse body as a xml string
  67. @param body: source body
  68. @return the xml string
  69. """
  70. if body is None:
  71. return
  72. dic = {}
  73. if isinstance(body, DaraModel):
  74. dic = body.to_map()
  75. elif isinstance(body, dict):
  76. dic = body
  77. if dic.__len__() == 0:
  78. return ""
  79. else:
  80. result_xml = '<?xml version="1.0" encoding="utf-8"?>'
  81. for k in dic:
  82. elem = ElementTree.Element(k)
  83. XML.__get_xml_factory(elem, dic[k])
  84. result_xml += bytes.decode(ElementTree.tostring(elem), encoding="utf-8")
  85. return result_xml