【问题标题】:Convert nested dict to xml将嵌套的dict转换为xml
【发布时间】:2021-08-24 11:38:05
【问题描述】:

我正在尝试使用 dict2xml 将嵌套字典转换为 xml。

这段代码:

from dict2xml import dict2xml

data = {
  'a': 1,
  'b': [2, 3],
  'c': {
    'd': [
      {'p': 9},
      {'o': 10}
    ],
    'e': 7
  }
}

print dict2xml(data, wrap="all", indent="  ")  

像这样生成正确的 xml:

<all>
  <a>1</a>
  <b>2</b>
  <b>3</b>
  <c>
    <d>
      <p>9</p>
    </d>
    <d>
      <o>10</o>
    </d>
    <e>7</e>
  </c>
</all>

但是,如果我更改 'd' --> 'z',并通过 data = collections.OrderedDict(data) 维护键的顺序,则 xml 中的顺序不正确,并且 'z' 在 'e 之后结束' 在 xml 中的 'c' 下,如下所示:

<all>
  <a>1</a>
  <b>2</b>
  <b>3</b>
  <c>
    <e>7</e>
    <z>
      <p>9</p>
    </z>
    <z>
      <o>10</o>
    </z>
  </c>
</all>

如何在不排序键顺序的情况下运行 dict2xml? 是否有另一种解决方案可以从我的 dict 制作 xml?

谢谢!

【问题讨论】:

  • 如果您需要密钥排序,请将您的原始数据更改为OrderedDict...
  • 很容易修复,非常感谢!
  • 很高兴我能帮上忙。我将该评论作为您可以接受的答案:)
  • 啊等等,不,它不维护字典中的顺序。例如,如果我将 'd' 更改为 'z',它会在 xml 中的 'e' 之后打印

标签: python xml dictionary nested


【解决方案1】:

正如@AKX 指出的那样,您还需要将collections.OrderedDict 应用于嵌套字典。您可以使用递归来完成此操作:

from collections import OrderedDict
def to_od(d):
   if not isinstance(d, (dict, list)):
      return d
   if isinstance(d, list):
       return list(map(to_od, d))
   return OrderedDict({a:to_od(b) for a, b in d.items()})

data = {'a': 1, 'b': [2, 3], 'c': {'d': [{'p': 9}, {'o': 10}], 'e': 7}}
print(to_od(data))

输出:

OrderedDict([('a', 1), ('b', [2, 3]), ('c', OrderedDict([('d', [OrderedDict([('p', 9)]), OrderedDict([('o', 10)])]), ('e', 7)]))])

但是,值得注意的是,将整个结构转换为 collections.OrderedDict 以及 dict2xml 将需要对数据进行两次遍历。使用自定义 dict-to-xml 转换器只需遍历一次:

def to_xml(d, indent="  "):
   def _to_xml(d, ind, p = None):
      if not isinstance(d, (dict, list)):
         yield f'{ind}<{p}>{d}</{p}>'
      elif isinstance(d, list):
         for i in d:
            yield from _to_xml(i, ind, p)
      else:
          p1, p2 = '' if p is None else f'{ind}<{p}>\n', '' if p is None else f'\n{ind}</{p}>'
          ind = ind if p is None else ind+indent
          for i in sorted(d): #sorting the keys
             if not isinstance(d[i], (dict, list)):
                yield f'{p1}{ind}<{i}>{d[i]}</{i}>{p2}'
             elif isinstance(d[i], dict):
                yield '{}{}<{}>\n{}\n{}</{}>{}'.format(p1, ind, i, '\n'.join(_to_xml(d[i], ind+indent)), ind, i, p2)
             else:
                yield from _to_xml(d[i], ind, p = i)
   return '<all>\n{}\n</all>'.format('\n'.join(_to_xml(d, indent)))

data = {'a': 1, 'b': [2, 3], 'c': {'d': [{'p': 9}, {'o': 10}], 'e': 7}}
print(to_xml(data))      

输出:

<all>
  <a>1</a>
  <b>2</b>
  <b>3</b>
  <c>
    <d>
      <p>9</p>
    </d>
    <d>
      <o>10</o>
    </d>
    <e>7</e>
  </c>
</all>

【讨论】:

    【解决方案2】:

    字典inherently don't have key order before Python 3.7,所以(让我的评论成为答案)如果您需要保证键顺序,请使用collections.OrderedDict

    【讨论】:

    • 它似乎不适用于字典中的字典。在生成名为data的字典时,我测试了将'd'改为'z',然后data= collections.OrderedDict(data)。执行dict2xml时,'e'打印在'c'下面,后面是'z'。
    • 你还需要制作任何嵌套的字典,如果有的话,OrderedDicts。
    • 我该如何处理上面的dict数据?
    猜你喜欢
    • 2021-06-02
    • 2014-09-23
    • 1970-01-01
    • 2018-12-06
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 2022-07-08
    相关资源
    最近更新 更多