我有一个XML文件,其数据结构如
<report>
<table>
<detail name="John" surname="Smith">
<detail name="Michael" surname="Smith">
<detail name="Nick" surname="Smith">
... {a lot of <detail> elements}
</table>
</report>
我需要检查属性为'name'=='surname'的元素。
XML文件大于1 GB,我在尝试 etree.parse(file)时出错。
如何使用Python和LXML逐个处理元素?
答案 0 :(得分:2)
考虑iterparse,它允许您在构建树时处理元素。下面检查 name 属性是否等同于 surname 属性。使用if
块进一步处理,例如有条件地将值附加到列表中:
import xml.etree.ElementTree as et
data = []
path = "/path/to/source.xml"
# get an iterable
context = et.iterparse(path, events=("start", "end"))
# turn it into an iterator
context = iter(context)
# get the root element
ev, root = next(context)
for ev, el in context:
if ev == 'start' and el.tag == 'detail':
print(el.attrib['name'] == el.attrib['surname'])
data.append([el.attrib['name'], el.attrib['surname']])
root.clear()
print(data)
# False
# False
# False
# [['John', 'Smith'], ['Michael', 'Smith'], ['Nick', 'Smith']]
答案 1 :(得分:1)
解析XML基本上有三种标准方法:
lxml
是对libxml
C库的绑定,它是DOM的实现,iterparse
方法似乎是StAX方法的实现。 SAX解析器内置于python本身:https://docs.python.org/3.6/library/xml.sax.html
对于您的情况,标准方法是使用SAX解析器。
答案 2 :(得分:0)
您可以使用iterparse
方法,该方法用于处理大型xml文件。但是,您的文件具有特别简单的结构。使用iterparse会不必要地复杂化。
我将在一个脚本中提供两个答案。我通过展示如何使用lxml解析xml中的行来直接回答你的问题,并且我使用正则表达式提供了我认为可能更好的答案。
代码读取xml中的每一行,并忽略那些不以'try ... except开头的行。当脚本找到这样一行时,它会从lxml将其传递给etree
进行解析,然后显示该行的属性。之后,它使用正则表达式来解析相同的属性并显示它们。
我强烈怀疑正则表达式会更快。
>>> from lxml import etree
>>> report = '''\
... <report>
... <table>
... <detail name="John" surname="Smith">
... <detail name="Michael" surname="Smith">
... <detail name="Nick" surname="Smith">
... </table>
... </report>'''
>>> import re
>>> re.search(r'name="([^"]*)"\s+surname="([^"]*)', line).groups()
('John', 'Smith')
>>> for line in report.split('\n'):
... if line.strip().startswith('<detail'):
... tree = etree.fromstring(line.replace('>', '/>'))
... tree.attrib['name'], tree.attrib['surname']
... re.search(r'name="([^"]*)"\s+surname="([^"]*)', line).groups()
...
('John', 'Smith')
('John', 'Smith')
('Michael', 'Smith')
('Michael', 'Smith')
('Nick', 'Smith')
('Nick', 'Smith')