使用Python lxml处理嵌套元素

时间:2014-10-14 20:52:36

标签: python xml lxml

鉴于以下简单的XML数据:

<book>
   <title>My First Book</title>
   <abstract>
         <para>First paragraph of the abstract</para>
         <para>Second paragraph of the abstract</para>
    </abstract>
    <keywordSet>
         <keyword>First keyword</keyword>
         <keyword>Second keyword</keyword>
         <keyword>Third keyword</keyword>
    </keywordSet>
</book>

如何使用lxml遍历树,并获取&#34; abstract&#34;中的所有段落。元素,以及&#34; keywordSet&#34;中的所有关键字;元件?

下面的代码片段仅返回每个元素中的第一行文字:

from lxml import objectify
root = objectify.fromstring(xml_string) # xml_string contains the XML data above
print root.title # returns the book title
for line in root.abstract:
    print line.para # returns only yhe first paragraph
for word in root.keywordSet:
    print word.keyword # returns only the first keyword in the set

我尝试关注this example,但上面的代码并没有按预期工作。

另一方面,更好的是能够将整个XML树读入Python字典,每个元素作为键,每个文本作为元素项。我发现使用lxml objectify可能会有类似的东西,但我无法弄清楚如何实现它。

我尝试在Python中编写XML解析代码时发现的一个非常大的问题是大多数&#34;示例&#34;提供的内容过于简单且完全虚构,无法提供太多帮助 - 否则它们恰恰相反,使用过于复杂的自动生成的XML数据!

有人可以给我一个提示吗?

提前致谢!

编辑:发布此问题后,我找到了一个简单的解决方案here

因此,我更新的代码变为:

from lxml import objectify
    root = objectify.fromstring(xml_string) # xml_string contains the XML data above
    print root.title # returns the book title
    for para in root.abstract.iterchildren():
        print para # now returns the text of all paragraphs
    for keyword in root.keywordSet.iterchildren():
        print keyword # now returns all keywords in the set

1 个答案:

答案 0 :(得分:6)

使用XPath

非常简单
from lxml import etree

tree = etree.parse('data.xml')

paragraphs = tree.xpath('/abstract/para/text()')
keywords = tree.xpath('/keywordSet/keyword/text()')

print paragraphs
print keywords

输出:

['First paragraph of the abstract', 'Second paragraph of the abstract']
['First keyword', 'Second keyword', 'Third keyword']

有关XPath语法的详细信息,请参阅the XPath Tutorial at W3Schools

特别是,上述表达式中使用的元素

  • /选择器,用于选择根节点/直接子节点。
  • text()运算符,用于选择相应元素的文本节点(&#34;文本内容&#34;)。

以下是使用Objectify API完成的方法:

from lxml import objectify

root = objectify.fromstring(xml_string)

paras = [p.text for p in root.abstract.para]
keywords = [k.text for k in root.keywordSet.keyword]

print paras
print keywords

对于root.abstract.pararoot.abstract.para[0]似乎实际为shorthand。因此,您需要明确使用element.iterchildren()来访问所有子元素。

这不是真的,我们显然都误解了Objectify API: 为了迭代para中的abstract,您需要迭代root.abstract.para,而不是root.abstract。这很奇怪,因为您直观地将abstract视为其节点的集合或容器,并且该容器将由Python可迭代表示。但它实际上是代表序列的.para选择器。