2010-02-20 100 views
4

我需要讀取大型XML(65 Mb),根據xsd對其進行驗證,並對其運行XPath查詢。下面,我已經給出了一個lxml版本。運行查詢需要很長時間(超過5分鐘),但驗證看起來非常快。具有XPath支持的快速python XML驗證器

我有幾個問題。性能卓越的Python程序員如何使用lxml編寫程序?其次,如果lxml不適合工作,還有什麼?你可以給一個代碼片段嗎?

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 
+0

請注意,65 Mb數據文件的列表(作者姓名)的預期大小爲320,000。這基本上是一個性能測試。 – Sumant

+0

感謝您發佈代碼:) – Viet

回答

0

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))) 
0

我不知道如果你可以重寫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()") 

如果文檔的結構允許這樣做可以更快。儘管如此,不應該成爲一個問題。

+0

考慮一下,我不認爲我的回答是非常正確的 - 您的xpath表達式已經是絕對的了(它不以'//'開頭)。儘管如此,5分鐘似乎相當長。 –

+0

我已經更新瞭解決此問題的答案。 –