设计笔记
通过@tdelaney答案基本上是正确的,但我要指出的Python元素树API的一个细微差别。下面是从the lxml
tutorial报价:
元素可以包含文本:
<root>TEXT</root>
在许多XML文档(数据为中心的文档),这是文本的地方可以找到的唯一地方。它由叶子标签封装在树层次结构的最底部。
但是,如果用于标记的文本文件,如(X)HTML XML,文本,也可能出现不同元素之间,就在树的中间:
<html><body>Hello<br/>World</body></html>
这里,<br/>
标签包围文本。这通常被称为文档样式或混合内容XML。元素通过它们的tail
属性支持这一点。它包含直接跟随元素的文本,直到XML树中的下一个元素。
这两个属性text
和tail
足以表示XML文档中的任何文本内容。这样,ElementTree API 除Element元素类之外不需要任何特殊的文本节点,这些节点往往会相当频繁地进行(正如您从传统DOM API中所了解的那样)。
实施
考虑这些特性考虑在内,可以不强制树输出的文本节点检索文档中的文本。
#!/usr/bin/env python3.3
import itertools
from pprint import pprint
try:
from lxml import etree
except ImportError:
from xml.etree import cElementTree as etree
def textAndElement(node):
'''In py33+ recursive generators are easy'''
yield node
text = node.text.strip() if node.text else None
if text:
yield text
for child in node:
yield from textAndElement(child)
tail = node.tail.strip() if node.tail else None
if tail:
yield tail
if __name__ == '__main__':
xml = '''
<species>
Mammals: <dog/> <cat/>
Reptiles: <snake/> <turtle/>
Birds: <seagull/> <owl/>
</species>
'''
doc = etree.fromstring(xml)
pprint(list(textAndElement(doc)))
#[<Element species at 0x7f2c538727d0>,
#'Mammals:',
#<Element dog at 0x7f2c538728c0>,
#<Element cat at 0x7f2c53872910>,
#'Reptiles:',
#<Element snake at 0x7f2c53872960>,
#<Element turtle at 0x7f2c538729b0>,
#'Birds:',
#<Element seagull at 0x7f2c53872a00>,
#<Element owl at 0x7f2c53872a50>]
gen = textAndElement(doc)
next(gen) # skip root
groups = []
for _, g in itertools.groupby(gen, type):
groups.append(tuple(g))
pprint(dict(zip(*[iter(groups)] * 2)))
#{('Birds:',): (<Element seagull at 0x7fc37f38aaa0>,
# <Element owl at 0x7fc37f38a820>),
#('Mammals:',): (<Element dog at 0x7fc37f38a960>,
# <Element cat at 0x7fc37f38a9b0>),
#('Reptiles:',): (<Element snake at 0x7fc37f38aa00>,
# <Element turtle at 0x7fc37f38aa50>)}
如果你看看你的权利...它看起来像第4个下相关应该指向你在正确的方向... –
你有控制的XML格式?通常,分类器(如Mammals等)表示为xml元素名称或属性(例如),以便xpath选择器很容易编写。 –
tdelaney
不,我不能更改XML。 – Alicia