py2xml.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #
  2. # Metrix++, Copyright 2009-2019, Metrix++ Project
  3. # Link: https://github.com/metrixplusplus/metrixplusplus
  4. #
  5. # This file is a part of Metrix++ Tool.
  6. #
  7. # Copied from http://code.activestate.com/recipes/577268-python-data-structure-to-xml-serialization/
  8. # - indent feature and better formatting added
  9. # - fixed handling of lists in lists
  10. # - fixed root object name for dictionaries
  11. INDENT_SPACE_SYMBOL = " "
  12. '''
  13. Py2XML - Python to XML serialization
  14. This code transforms a Python data structures into an XML document
  15. Usage:
  16. serializer = Py2XML()
  17. xml_string = serializer.parse( python_object )
  18. print python_object
  19. print xml_string
  20. '''
  21. class Py2XML():
  22. digitCount = 0
  23. def __init__( self, digitCount = None ):
  24. self.data = "" # where we store the processed XML string
  25. if digitCount != None:
  26. self.digitCount = digitCount
  27. else:
  28. self.digitCount = 8
  29. def parse( self, pythonObj, objName=None, indent = 0 ):
  30. '''
  31. processes Python data structure into XML string
  32. needs objName if pythonObj is a List
  33. '''
  34. if pythonObj == None:
  35. return "\n" + (INDENT_SPACE_SYMBOL * indent) + ""
  36. if isinstance( pythonObj, dict ):
  37. self.data = self._PyDict2XML( pythonObj, objName, indent=indent+1 )
  38. elif isinstance( pythonObj, list ):
  39. # we need name for List object
  40. self.data = self._PyList2XML( pythonObj, objName, indent=indent+1 )
  41. else:
  42. self.data = "\n" + (INDENT_SPACE_SYMBOL * indent) + "<%(n)s>%(o)s</%(n)s>" % { 'n':objName, 'o':str( pythonObj ) }
  43. return self.data
  44. def _PyDict2XML( self, pyDictObj, objName=None, indent = 0 ):
  45. '''
  46. process Python Dict objects
  47. They can store XML attributes and/or children
  48. '''
  49. tagStr = "" # XML string for this level
  50. attributes = {} # attribute key/value pairs
  51. attrStr = "" # attribute string of this level
  52. childStr = "" # XML string of this level's children
  53. for k, v in sorted(list(pyDictObj.items())):
  54. if isinstance( v, dict ):
  55. # child tags, with attributes
  56. childStr += self._PyDict2XML( v, k, indent=indent+1 )
  57. elif isinstance( v, list ):
  58. # child tags, list of children
  59. childStr += self._PyList2XML( v, k, indent=indent+1 )
  60. else:
  61. # tag could have many attributes, let's save until later
  62. attributes.update( { k:v } )
  63. if objName == None:
  64. return childStr
  65. # create XML string for attributes
  66. for k, v in sorted(attributes.items()):
  67. if isinstance(v, float):
  68. attrStr += " %s=\"%s\"" % ( k, round(v, self.digitCount) )
  69. else:
  70. attrStr += " %s=\"%s\"" % ( k, v )
  71. # let's assemble our tag string
  72. if childStr == "":
  73. tagStr += "\n" + (INDENT_SPACE_SYMBOL * indent) + "<%(n)s%(a)s />" % { 'n':objName, 'a':attrStr }
  74. else:
  75. tagStr += ("\n" + (INDENT_SPACE_SYMBOL * indent) + "<%(n)s%(a)s>%(c)s" + "\n" + (INDENT_SPACE_SYMBOL * indent) + "</%(n)s>") % { 'n':objName, 'a':attrStr, 'c':childStr }
  76. return tagStr
  77. def _PyList2XML( self, pyListObj, objName=None, indent = 0 ):
  78. '''
  79. process Python List objects
  80. They have no attributes, just children
  81. Lists only hold Dicts or Strings
  82. '''
  83. tagStr = "" # XML string for this level
  84. childStr = "" # XML string of children
  85. for childObj in pyListObj:
  86. if isinstance( childObj, dict ):
  87. # here's some Magic
  88. # we're assuming that List parent has a plural name of child:
  89. # eg, persons > person, so cut off last char
  90. # name-wise, only really works for one level, however
  91. # in practice, this is probably ok
  92. childStr += self._PyDict2XML( childObj, objName[:-1], indent=indent+1 )
  93. elif isinstance( childObj, list ):
  94. # here's some Magic
  95. # we're assuming that List parent has a plural name of child:
  96. # eg, persons > person, so cut off last char
  97. # name-wise, only really works for one level, however
  98. # in practice, this is probably ok
  99. childStr += self._PyList2XML( childObj, objName[:-1], indent=indent+1 )
  100. pass
  101. else:
  102. childStr += "\n" + (INDENT_SPACE_SYMBOL * (indent + 1)) + "<" + objName[:-1] + ">"
  103. for string in childObj:
  104. childStr += str(string);
  105. childStr += "</" + objName[:-1] + ">"
  106. if objName == None:
  107. return childStr
  108. tagStr += ("\n" + (INDENT_SPACE_SYMBOL * indent) + "<%(n)s>%(c)s" + "\n" + (INDENT_SPACE_SYMBOL * indent) + "</%(n)s>") % { 'n':objName, 'c':childStr }
  109. return tagStr