[英]Processing large XML file with libxml-ruby chunk by chunk
我想在Ruby中使用libxml讀取包含超過一百萬個小書目記錄(如<article>...</article>
)的大型XML文件。 我已經嘗試將Reader類與expand
方法結合使用來按記錄讀取記錄,但我不確定這是正確的方法,因為我的代碼占用了內存。 因此,我正在尋找一個如何方便地處理記錄的配方,並且內存使用量不斷增加。 以下是我的主循環:
File.open('dblp.xml') do |io|
dblp = XML::Reader.io(io, :options => XML::Reader::SUBST_ENTITIES)
pubFactory = PubFactory.new
i = 0
while dblp.read do
case dblp.name
when 'article', 'inproceedings', 'book':
pub = pubFactory.create(dblp.expand)
i += 1
puts pub
pub = nil
$stderr.puts i if i % 10000 == 0
dblp.next
when 'proceedings','incollection', 'phdthesis', 'mastersthesis':
# ignore for now
dblp.next
else
# nothing
end
end
end
這里的關鍵是dblp.expand
讀取整個子樹(如<article>
記錄)並將其作為參數傳遞給工廠以進行進一步處理。 這是正確的方法嗎?
在工廠方法中,我然后使用類似高級XPath的表達式來提取元素的內容,如下所示。 再說一次,這可行嗎?
def first(root, node)
x = root.find(node).first
x ? x.content : nil
end
pub.pages = first(node,'pages') # node contains expanded node from dblp.expand
處理XML時,兩個常見選項是基於樹的,基於事件的。 基於樹的方法通常讀取整個XML文檔,並且可能消耗大量內存。 基於事件的方法不使用額外的內存,但除非您編寫自己的處理程序邏輯,否則不會執行任何操作。
基於事件的模型由SAX樣式的解析器和衍生實現使用。
REXML示例: http : //www.iro.umontreal.ca/~lapalme/ForestInsteadOfTheTrees/HTML/ch08s01.html
REXML: http : //ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html
我有同樣的問題,但我想我通過調用Node#remove來解決它! 在展開的節點上。 在你的情況下,我認為你應該做的事情
my_node = dblp.expand [do what you have to do with my_node] dblp.next my_node.remove!
不確定為什么會這樣,但是如果你看一下LibXML :: XML :: Reader#expand的源代碼,就會有關於釋放節點的評論。 我猜測Reader#expand將節點關聯到Reader,你必須調用Node #remove! 釋放它。
即使有這種黑客攻擊,內存使用也不是很好,但至少它沒有繼續增長。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.