2013-03-14 65 views
8

我需要解析一個非常大的(〜40GB)XML文件,從中刪除某些元素,並將結果寫入新的xml文件。我一直試圖從python的ElementTree中使用iterparse,但是我對如何修改樹並將結果樹寫入新的XML文件感到困惑。我已經閱讀了關於itertree的文檔,但它並沒有解決問題。有沒有簡單的方法來做到這一點?使用python ElementTree的itertree函數並將修改後的樹寫入輸出文件

謝謝!

編輯:這是我到目前爲止。

import xml.etree.ElementTree as ET 
import re 

date_pages = [] 
f=open('dates_texts.xml', 'w+') 

tree = ET.iterparse("sample.xml") 

for i, element in tree: 
    if element.tag == 'page': 
     for page_element in element: 
      if page_element.tag == 'revision': 
       for revision_element in page_element: 
        if revision_element.tag == '{text': 
         if len(re.findall('20\d\d', revision_element.text.encode('utf8'))) == 0: 
          element.clear() 
+0

您能否顯示您嘗試的代碼(即使它不完整)?幫助你修復它而不是從頭開始寫東西會節省時間。 – 2013-03-14 02:07:35

+0

在上面的代碼中添加了我的問題。 – LateCoder 2013-03-15 02:56:12

+0

我早些發現了。對不起,我一直在忙着其他的事情,但我保證我會盡快看看。與此同時,我提出了關於聊天的問題,以引起更多關注。 – 2013-03-15 02:58:24

回答

1

也許my similar question的答案可以幫助你。

至於怎麼寫這回的.xml文件,我結束了我的腳本的底部這樣做:

with open('File.xml', 'w') as t: # I'd suggest using a different file name here than your original 
    for line in ET.tostring(doc): 
     t.write(line) 
    t.close 
print('File.xml Complete') # Console message that file wrote successfully, can be omitted 

變量doc是早期在我的腳本,可比的地方你有tree = ET.iterparse("sample.xml")我有這樣的:

doc = ET.parse(filename) 

我一直在使用lxml的,而不是ElementTree的,但我覺得寫出來的部分應該仍然工作(我認爲這主要是公正的XPath東西,ElementTree中不能處理的。)我使用與此導入的lxml行:

from lxml import etree as ET 

希望這(我的,因爲如果你需要一些額外的代碼上下文鏈接的問題一起)可以幫助你!

+1

要在修改文件後將'tree = ET.parse(source)'寫入文件,可以使用:'tree.write('File.xml')'。注意:你的代碼'for ET.tostring(doc)'一次寫入*一個*字符。如果你想使用'ET.tostring()';你可以一次寫入't.write(ET.tostring(doc))'。 'with'語句自動關閉文件,你不需要't.close()'。請參閱我的答案中的示例[如何編寫大型和小型XML文件](http://stackoverflow.com/a/15457389/4279) – jfs 2013-03-17 04:09:24

6

如果你有一個大的xml不適合內存,那麼你可以嘗試一次對它的一個元素進行序列化。例如,假設<root><page/><page/><page/>...</root>文檔結構,而忽略可能的命名空間的問題:

import xml.etree.cElementTree as etree 

def getelements(filename_or_file, tag): 
    context = iter(etree.iterparse(filename_or_file, events=('start', 'end'))) 
    _, root = next(context) # get root element 
    for event, elem in context: 
     if event == 'end' and elem.tag == tag: 
      yield elem 
      root.clear() # free memory 

with open('output.xml', 'wb') as file: 
    # start root 
    file.write(b'<root>') 

    for page in getelements('sample.xml', 'page'): 
     if keep(page): 
      file.write(etree.tostring(page, encoding='utf-8')) 

    # close root 
    file.write(b'</root>') 

其中keep(page)回報True如果page應保持如:

import re 

def keep(page): 
    # all <revision> elements must have 20xx in them 
    return all(re.search(r'20\d\d', rev.text) 
       for rev in page.iterfind('revision')) 

爲了比較,修改 XML文件,您可以:

# parse small xml 
tree = etree.parse('sample.xml') 

# remove some root/page elements from xml 
root = tree.getroot() 
for page in root.findall('page'): 
    if not keep(page): 
     root.remove(page) # modify inplace 

# write to a file modified xml tree 
tree.write('output.xml', encoding='utf-8') 
+0

有沒有辦法讓圖書館打印出''和' '爲你保留屬性,例如,在開始標記中的名稱空間聲明,而不保留根元素的內存? – binki 2016-01-13 21:11:58

+0

@binki:你在'getelements()'中看到'root'變量嗎?你認爲它指的是什麼? – jfs 2016-01-14 06:40:08

+0

爲什麼你有'file.write(b'')'那麼? – binki 2016-01-14 06:50:09