2011-07-22 100 views
4

編輯:我決定採用LINQ to XML的方法(請參閱下面的答案),這是推薦的,一切正常,除非我無法用來自增量文件。我設法通過刪除整個文件節點然後添加到增量節點來使程序工作。有沒有辦法只是交換它們呢?另外,雖然這個解決方案非常好,但有什麼方法可以減少內存使用量而不會丟失LINQ代碼?這個解決方案可能仍然有效,但我願意犧牲時間來降低內存使用量。C#查找和替換XML節點


我試圖把兩個XML文件(一個完整的文件和一個增量文件)合併在一起。 XML文件是這樣的:

<List> 
    <Records> 
     <Person id="001" recordaction="add"> 
      ... 
     </Person> 
    </Records> 
</List> 

的recordaction屬性也可以是「CHG」更改或「刪除」的刪除。我的程序的基本邏輯是:

1)將完整文件讀入XmlDocument。

2)將增量文件讀入XmlDocument,使用XmlDocument.SelectNodes()選擇節點,將這些節點放入字典中以便於搜索。

3)選擇完整文件中的所有節點,遍歷並檢查包含增量記錄的字典。如果recordaction =「chg」或「del」將該節點添加到列表中,則從該列表中的XmlNodeList中刪除所有節點。最後,將增量文件中的recordaction =「chg」或「add」記錄添加到完整文件中。

4)保存XML文件。

我有一些嚴重的問題步驟3.下面是該函數的代碼:

private void ProcessChanges(XmlNodeList nodeList, Dictionary<string, XmlNode> dictNodes) 
    { 
     XmlNode lastNode = null; 
     XmlNode currentNode = null; 
     List<XmlNode> nodesToBeDeleted = new List<XmlNode>(); 

     // If node from full file matches to incremental record and is change or delete, 
     // mark full record to be deleted. 
     foreach (XmlNode fullNode in fullDocument.SelectNodes("/List/Records/Person")) 
     { 
      dictNodes.TryGetValue(fullNode.Attributes[0].Value, out currentNode); 
      if (currentNode != null) 
      { 
       if (currentNode.Attributes["recordaction"].Value == "chg" 
        || currentNode.Attributes["recordaction"].Value == "del") 
       { 
        nodesToBeDeleted.Add(currentNode); 
       } 
      } 
      lastNode = fullNode; 
     } 

     // Delete marked records 
     for (int i = nodeList.Count - 1; i >= 0; i--) 
     { 
      if(nodesToBeDeleted.Contains(nodeList[i])) 
      { 
       nodeList[i].ParentNode.RemoveChild(nodesToBeDeleted[i]); 
      } 
     } 

     // Add in the incremental records to the new full file for records marked add or change. 
     foreach (XmlNode weeklyNode in nodeList) 
     { 
      if (weeklyNode.Attributes["recordaction"].Value == "add" 
       || weeklyNode.Attributes["recordaction"].Value == "chg") 
      { 
       fullDocument.InsertAfter(weeklyNode, lastNode); 
       lastNode = weeklyNode; 
      } 
     } 
    } 

的XmlNodeList中的傳遞只是所有從增量文件中選拔出來的,增量記錄,字典就是那些相同的節點,但是在ID上鍵入的,所以我不必每次都循環遍歷所有的增量記錄。由於索引超出界限,此時該程序正在「刪除標記的記錄」階段死亡。我很確定「添加增量記錄」也不起作用。有任何想法嗎?還有一些關於提高效率的建議很好。我可能會遇到一個問題,因爲它正在讀取一個250MB的文件,這個文件在內存中擴展到750MB,所以我想知道在整個文件中是否有逐個節點的更簡單的方法。謝謝!

+2

作爲一個友好的建議。使用LINQ to XML進行XML操作。使用XDocument,XElement,XAttribute等。使用System.Xml.Linq命名空間。 :) –

+0

我會看看LINQ。感謝您的建議! –

回答

5

下面是一個如何使用LINQ到XML實現它的例子。不需要字典:

using System.Xml.Linq; 

// Load the main and incremental xml files into XDocuments 
XDocument fullFile = XDocument.Load("fullfilename.xml"); 
XDocument incrementalFile = XDocument.Load("incrementalfilename.xml");  

// For each Person in the incremental file 
foreach (XElement person in incrementalFile.Descendants("Person")) { 

    // If the person should be added to the full file 
    if (person.Attribute("recordaction").Value == "add") { 
     fullFile.Element("List").Element("Records").Add(person); // Add him 
    } 

    // Else the person already exists in the full file 
    else { 
     // Find the element of the Person to delete or change 
     var personToChange = 
       (from p in fullFile.Descendants("Person") 
        where p.Attribute("id").Value == person.Attribute("id").Value 
        select p).Single(); 

     // Perform the appropriate operation 
     switch (person.Attribute("recordaction").Value) { 
      case "chg": 
       personToChange.ReplaceWith(person); 
       break; 
      case "del": 
       personToChange.Remove(); 
       break; 
      default: 
       throw new ApplicationException("Unrecognized attribute"); 
     } 
    } 
}// end foreach 

// Save the changes to the full file 
fullFile.Save("fullfilename.xml"); 

請讓我知道如果您有任何問題運行它,我會編輯和修復它。我很確定這是正確的,但目前沒有VS可用。

編輯:修正了「變種」的情況下使用personToChange.ReplaceWith(人),而不是'personToChange =人'。後者不會取代任何東西,因爲它只是將參考文獻從基礎文檔中移開。

+0

我會給這個鏡頭。萬分感謝! –

+0

糟糕,我只注意到我錯過了「List」元素。我編輯了代碼來修復它。希望你能在嘗試之前看到變化。 –

+0

我得到了您的編輯,它看​​起來像添加和刪除的記錄在新文件中,但它看起來像替換出更改的記錄可能有問題。我查看了增量文件中的「chg」,它是完整文件中的「添加」,並且它仍然是新文件中的「添加」。你確定只是設置personToChange = person將與文件同步嗎?我想我可以嘗試刪除然後添加以及。 –