我想用python的dicts列表创建嵌套的XML(作为字符串):
toc = [
{'entryno': 1, 'level': 1, 'pageno': 17, 'title': 'title a'},
{'entryno': 2, 'level': 2, 'pageno': 19, 'title': 'title b'},
{'entryno': 3, 'level': 1, 'pageno': 25, 'title': 'title c'},]
级别表示嵌套级别,我的dict中可能有超过2个级别。 toc具有固定的排序(通过entryno)。级别只能从一个条目增加到下一个条目,但可能会减少一个以上。 这是我想要创建的嵌套示例XML:
<entry id="1">
<pageno>17</pageno>
<title>title a</title>
<entry id="2">
<pageno>19</pageno>
<title>title b</title>
</entry>
</entry>
<entry id="3">
<pageno>25</pageno>
<title>title c</title>
</entry>
我尝试用string.Template()解决这个问题并迭代toc,但我仍然坚持创建XML的嵌套部分。我怀疑解决方案将是一些递归的东西。
作为编程初学者,我不仅对解决方案感兴趣,而且还在您的思路中解决这个问题!
答案 0 :(得分:4)
使用ElementTree API的非丑陋解决方案。 Python包含一个实现,如xml.etree。[c] ElementTree。另一个是lxml.etree,它提供了更多功能,包括漂亮打印输出。
# import xml.etree.cElementTree as et
import lxml.etree as et
import sys
toc = [
{'entryno': 1, 'level': 1, 'pageno': 17, 'title': 'title a'},
{'entryno': 2, 'level': 2, 'pageno': 19, 'title': 'title b'},
{'entryno': 3, 'level': 1, 'pageno': 25, 'title': 'Smith & Wesson'},
{'entryno': 4, 'level': 2, 'pageno': 27, 'title': '<duct tape>'},
{'entryno': 5, 'level': 2, 'pageno': 29, 'title': u'\u0404'},
]
root = et.Element("root")
tree = et.ElementTree(root)
parent = {0: root}
for entry in toc:
level = entry['level']
entryno = entry['entryno']
# create the element and link it to its parent
elem = et.SubElement(parent[level - 1], "entry", {'id': str(entryno)})
# create children to hold the other data items
for k, v in entry.iteritems():
if k in ('entryno', 'level'): continue
child = et.SubElement(elem, k)
child.text = unicode(v)
# record current element as a possible parent
parent[level] = elem
# tree.write(sys.stdout)
tree.write(sys.stdout, pretty_print=True)
答案 1 :(得分:1)
假设您知道如何创建XML。
假设数据嵌套在前一个节点中,数据中的“级别”会增加,并且只会增加1.如果级别降低,这意味着您不再讨论当前节点,而是关于上面的一些节点; level == 1表示'在文档级附加'。
要处理增加级别,您只需要跟踪上一个节点。如果级别增加1,则创建一个新节点并使其成为上一个节点的子节点。
要处理相同的级别,您需要记住以前创建的节点的父级。您将新节点附加到该父节点,因为它是前一节点的对等节点。
要处理降低级别,您需要从上一个节点退回几个步骤,以便您处于正确的级别。你能看到一种模式吗?
您真的需要记住从文档级到先前创建的节点的整个链。如果next_node.level == previous_node.level + 1
,则将其附加到链的末尾。否则,您将链上的previous_node.level - next_node.level + 1
项退回并使用该节点作为父节点。我们假设0级是文档级别。
一些代码来说明这一点:
def nest(input):
ret = {'level': 0} # 'document level'
path = [ret]
for item in input:
node = dict(item) # a copy of item, lest we alter input
old_level = path[-1]['level'] # last element's
new_level = node['level']
delta = new_level - old_level - 1
if delta < 0:
path = path[:delta]
children_list = path[-1].get('_children', None) or []
children_list.append(node)
path[-1]['_children'] = children_list
path.append(node)
return ret
from pprint import PrettyPrinter
pr = PrettyPrint(indent=2).pprint
pr(nest(toc))
你看到了
{ '_children': [ { '_children': [ { 'entryno': 2,
'level': 2,
'pageno': 19,
'title': 'title b'}],
'entryno': 1,
'level': 1,
'pageno': 17,
'title': 'title a'},
{ 'entryno': 3, 'level': 1, 'pageno': 25, 'title': 'title c'}],
'level': 0}
在_children
下,我们列出了嵌套节点。
答案 2 :(得分:0)
toc = [
{'entryno': 1, 'level': 1, 'pageno': 17, 'title': 'title a'},
{'entryno': 2, 'level': 2, 'pageno': 18, 'title': 'title d'},
{'entryno': 3, 'level': 3, 'pageno': 19, 'title': 'title e'},
{'entryno': 4, 'level': 4, 'pageno': 20, 'title': 'title b'},
{'entryno': 5, 'level': 5, 'pageno': 25, 'title': 'title c'},]
blevel=0
ret=""
for i in toc:
while blevel >= i['level']:
ret += "%s</entry>\n" % (" " * blevel)
blevel-=1
blevel=i['level']
ident=" " * i['level']
ret += "%s<entry id=\"%i\">\n" % (ident, i['entryno'])
ident+=" "
for a in i:
if not a in ['entryno','level']:
ret += "%s<%s>%s</%s>\n" % (ident,a,i[a],a)
while blevel > 0:
ret += "%s</entry>\n" % (" " * blevel)
blevel-=1
print ret