2012-02-28 13 views
4

我需要遍歷大型XML文件(〜2GB)並選擇性地將某些節點複製到一個或多個單獨的XML文件。迭代大型XML文件和複製選擇節點

我首先想到的是使用XPath通過匹配節點和哪些其他文件(S)的節點應該被複制到每一個節點測試迭代,像這樣:

var doc = new XPathDocument(@"C:\Some\Path.xml"); 
var nav = doc.CreateNavigator(); 
var nodeIter = nav.Select("//NodesOfInterest"); 
while (nodeIter.MoveNext()) 
{ 
    foreach (Thing thing in ThingsThatMightGetNodes) 
    { 
     if (thing.AllowedToHaveNode(nodeIter.Current)) 
     { 
      thing.WorkingXmlDoc.AppendChild(... nodeIter.Current ...); 
     } 
    } 
} 

在該實現中,Thing定義public System.Xml.XmlDocument WorkingXmlDoc來保存它是AllowedToHave()的節點。不過,我不明白如何創建一個新的XmlNode,它是nodeIter.Current的副本。

如果還有更好的方法,我很樂意聽到它。

+0

要在2GB XML文檔上使用XPath,您的計算機必須具有> 10GB RAM,可能> 16GB。是這樣嗎? – 2012-02-28 23:57:10

+0

@DimitreNovatchev:是的,我不知道XPath需要這麼多的RAM,而且看起來很浪費(這是一個服務器,其他進程肯定會受到影響)。你能提出一個不同的解決方案嗎 – 2012-02-29 00:05:52

+0

我推薦使用XmlReader - 因此您不限制RAM。你的邏輯將保持大致相同。 – 2012-02-29 00:12:55

回答

3

評估XPath表達式需要將整個XML文檔(XML Infoset)放在RAM中。

對於其文本表示超過2GB的XML文件,通常需要超過10GB的RAM才能保存XML文檔。因此,儘管不是不可能,但它可能是優選的(尤其是在必須有許多請求可快速獲得資源的服務器上)才能使用其他技術。

XmlReader(基於類)是此場景的絕佳工具。它是快速的,僅向前傳送,並且不需要將讀取節點保留在內存中。此外,你的邏輯將保持幾乎相同。

1

您應該考慮LINQ to XML。檢查這個博客帖子的細節和例子:

http://james.newtonking.com/archive/2007/12/11/linq-to-xml-over-large-documents.aspx

+1

LINQ to XML如何用〜2GB輸入文件執行? – 2012-02-29 01:11:27

+0

直線上升,可能不是那麼好。但是你可以針對流進行操作。請參閱:http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx#Y1392。 – 2012-02-29 01:47:41

+0

非常酷! – 2012-02-29 03:01:01

0

嘗試實現文檔投影(一個想法首先由馬里昂和西蒙出版)的XQuery處理器。它在包括Saxon-EE在內的許多處理器中實施。基本上,如果您運行諸如// x之類的查詢,它將過濾輸入事件流並構建僅包含處理此查詢所需信息的樹;它會以正常的方式執行查詢,但是會對較小的樹進行查詢。如果這只是整個文檔的一小部分,您可以輕鬆地將內存需求減少95%左右。