【问题标题】:Fast python XML validator with XPath support支持 XPath 的快速 python XML 验证器
【发布时间】:2011-01-19 03:37:04
【问题描述】:

我需要读取一个大型 XML (65 Mb),根据 xsd 对其进行验证,并在其上运行 XPath 查询。下面,我给出了一个 lxml 版本。运行查询需要很长时间(超过 5 分钟),但验证似乎很快。

我有几个问题。注重性能的 Python 程序员如何使用 lxml 编写程序?其次,如果 lxml 不适合这份工作,还有什么?可以给个代码sn-p吗?

import sys
from datetime import datetime
from lxml import etree

start = datetime.now()
schema_file = open("library.xsd")
schema = etree.XMLSchema(file=schema_file)
parser = etree.XMLParser(schema = schema)
data_file = open(sys.argv[1], 'r')
tree = etree.parse(data_file, parser)
root = tree.getroot()
data_file.close()
schema_file.close()
end = datetime.now()
delta = end-start
print "Parsing time = ", delta

start = datetime.now()
name_list = root.xpath("book/author/name/text()")
print ("Size of list = " + str(len(name_list)))
end = datetime.now()
delta = end-start
print "Query time = ", delta

【问题讨论】:

  • 请注意,65 Mb 数据文件的列表(作者姓名)的预期大小为 320,000。这基本上是一个性能测试。
  • +1 感谢您发布代码 :)

标签: python xml validation xpath xsd


【解决方案1】:

我想知道你是否可以重写 xpath 表达式以更快地运行?可能有效的一件事是避免构建 name_list 节点集(如果您以后不需要它)并在 lxml 中计算节点。像这样的:

start = datetime.now()
name_list_len = root.xpath("count(/book/author/name/text())")
print ("Size of list = " + str(name_list_len))
end = datetime.now()

否则,您可能会发现 expat parser 提取文本的速度更快,但它无法验证,并且使用起来更复杂(您需要编写一个状态机和几个回调)。如果您只需要文本,使用C implementation of the element tree API 可能会更快。 lxml benchmarks 使阅读变得有趣,并且似乎暗示您可以更快地提取文本。

一个常见的 xpath 性能问题是在表达式开头不必要地使用“//”。在这种情况下,使表达式成为绝对表达式,例如:

 name_list = root.xpath("/rootelement/book/author/name/text()")

如果文档的结构允许这样做,速度会快很多。不过这里应该不是问题。

【讨论】:

  • 想一想,我认为我的回答不太正确——你的xpath表达式已经是绝对的(它不是以'//'开头的)。不过,5 分钟似乎相当长。
【解决方案2】:

lxml benchmarks 非常有用。在我看来,使用 XPath 提取元素节点很快,但提取文本可能很慢。下面,我提供了三个非常快的解决方案。

def bench_lxml_xpath_direct(root): # Very slow but very fast if text() is removed.
  name_list = root.xpath("book/author/name/text()")
  print ("Size of list = " + str(len(name_list)))

def bench_lxml_xpath_loop(root): # Fast
  name_list = root.xpath("book/author/name")
  result = []
  for n in name_list:
    result.append(n.text)

  print ("Size of list = " + str(len(name_list)))

def bench_lxml_getiterator(tree): # Very fast
  result = []
  for name in tree.getiterator("name"):
    result.append(name.text)
  print ("Size of list = " + str(len(result)))


def bench_lxml_findall(tree):  # Superfast
  result = []
  for name in tree.findall("//name"):
    result.append(name.text)
  print ("Size of list = " + str(len(result)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 1970-01-01
    • 2017-09-24
    • 2015-01-19
    • 2012-04-15
    相关资源
    最近更新 更多