2012-12-10 49 views
1

我正在使用C#中的解析器從多個xml文件獲取數據並將它們放入我自己的數據庫中。Linq to XML單獨處理結果而不是列表

現在我有這個代碼的工作原理:

List<CaseFile> caseFiles = 
      (
       from e in XDocument.Load(xmlDoc).Root.Elements("application-information").Elements("file-segments").Elements("action-keys").Elements("case-file") 
       select new CaseFile 
       { (......) 
}).toList(); 

這將創建CaseFile對象,我以後再發送給其他方法將它們的數據放入我的數據庫的列表。這個問題是我需要一次解析許多文件,有些大到1GB,但不能小於200MB,這就造成了對內存的巨大需求。

有沒有辦法修改我的語句,以便找到每個CaseFile,它會立即將其發送給其他方法,而不必先創建它們的完整列表?

回答

3

XDocument.Load將首先將整個文件加載到內存中。爲了快速搜索元素返回CaseFire對象IEnumerable和使用XmlReader讀取由節點文件節點(假設你只有在root/application-information/file-segments/action-keyscase-file節點,否則你將在這裏需要更多的邏輯):

static IEnumerable<CaseFile> FindCaseFiles(string uri) 
{ 
    using (XmlReader reader = XmlReader.Create(uri)) 
    { 
     reader.MoveToContent(); 

     while (reader.Read()) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.Element: 
        if (reader.Name == "case-file") 
        { 
         XElement el = XElement.ReadFrom(reader) as XElement; 
         if (el != null) 
          yield return new CaseFile() {...}; 
        } 
        break; 
      } 
     } 
    } 
} 

用法:

foreach(CaseFile file in FindCaseFiles(path_to_xml)) 
{ 
    // we have CaseFile here immediately after it found in xml file 
} 
+0

該解決方案看起來像我想要的,但我遇到麻煩實施它。爲了使它工作,我必須使CaseFile類實現IEnumerable,但現在我必須讓它實現IEnumerator的方法,我不確定這是甚至在邏輯上是正確的(它似乎正在使CaseFiles成爲一個對象列表,它只是一個對象我想做一個列表)...它告訴我它現在不包含「添加」的定義(錯誤指向linq查詢的「from ...」行),我甚至沒有知道如何實現... – ConnorU

+0

@ConnorU抱歉,沒有得到 - 爲什麼CaseFile應該實現IEnumerable? –

+0

編譯器告訴我這麼...我把你建議的代碼,它不會運行,因爲它說CaseFile沒有實現它...「錯誤無法初始化類型'TrademarkParserproject.CaseFile'的集合初始值設定項,因爲它沒有實現'System.Collections。IEnumerable'「 – ConnorU

0

只需刪除ToList並將您的變量聲明爲IEnumerable(或者只是使用var)就可以做到這一點。 使用linq to XML可能不會爲大文件指示,因爲它將所有文件加載到內存中。您應該考慮使用àXmlReader而不是

+0

你是什麼意思放下它?我把它放在什麼地方,讓它爲數據庫中的evry casefile創建一個casefile,一次? 另外,你會建議什麼替代linq-to-xml? – ConnorU

+0

什麼都沒有! Linq select用想要的'流式傳輸'行爲創建一個枚舉 –

+1

考慮使用àXmlReader作爲例子。 À有點難以使用,但內存更友好 –

0

這裏的問題在於你對LINQ表達式的結果調用ToList。這將枚舉所有值並將所有內容寫入內存。 LINQ-Expression本身並沒有列舉出這些值。它只會返回一個IEnumerable。 LINQ-Expression不會創建CaseFile對象。

如果你只是通過LINQ表達式的結果,循環它將讀取一個接一個的值:

var caseFiles = from e in XDocument.Load(xmlDoc).Root. 
        Elements("application-information"). 
        Elements("file-segments"). 
        Elements("action-keys"). 
        Elements("case-file") 
       select new CaseFile { ... }; 

foreach (CaseFile cf in caseFiles) 
{ 
    DoTheWork(cf); 
} 

這種方式只有一個CaseFile對象將在任何時間被創建。