2012-08-11 94 views
4

我需要一個XML文件並從輸入文件的重複節點創建多個輸出xml文件。源文件 「AnimalBatch.xml」 看起來是這樣的:將XML文檔拆分爲創建重複元素的多個輸出文件

<?xml version="1.0" encoding="utf-8" ?>
<Animals>
<Animal id="1001">
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>
<Animal id="1002">
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>
<Animal id="1003">
<Quantity>Three</Quantity>
<Color>Blind</Color>
<Name>Mice</Name>
</Animal>
</Animals>

程序需要拆分的重複 「動物」,併產生3個文件命名爲:Animal_1001.xml,Animal_1002。 xml和Animal_1003.xml

每個輸出文件應該只包含它們各自的元素(這將是根)。 AnimalsBatch.xml中的id屬性將爲Animal_xxxx.xml文件名提供序列號。 id屬性不需要在輸出文件中。


Animal_1001.xml:
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>One</Quantity>
<Adjective>Red</Adjective>
<Name>Rooster</Name>
</Animal>


Animal_1002.xml
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Two</Quantity>
<Adjective>Stubborn</Adjective>
<Name>Donkeys</Name>
</Animal>


Animal_1003.xml>
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>Three</Quantity>
<Adjective>Blind</Adjective>
<Name>Mice</Name>
</Animal>

我想與XmlDocument的做到這一點,因爲它需要能夠運行。Net 2.0。

我的計劃是這樣的:

static void Main(string[] args) 
    { 
     string strFileName;  
     string strSeq;      

     XmlDocument doc = new XmlDocument(); 
     doc.Load("D:\\Rick\\Computer\\XML\\AnimalBatch.xml"); 

     XmlNodeList nl = doc.DocumentElement.SelectNodes("Animal"); 

     foreach (XmlNode n in nl) 
     { 
      strSeq = n.Attributes["id"].Value; 

      XmlDocument outdoc = new XmlDocument(); 
      XmlNode rootnode = outdoc.CreateNode("element", "Animal", ""); 

      outdoc.AppendChild(rootnode); // Put the wrapper element into outdoc 

      outdoc.ImportNode(n, true); // place the node n into outdoc 
      outdoc.AppendChild(n);  // This statement errors: 
      // "The node to be inserted is from a different document context." 

      strFileName = "Animal_" + strSeq + ".xml"; 

      outdoc.Save(Console.Out); 
      Console.WriteLine(); 
     } 
     Console.WriteLine("END OF PROGRAM: Press <ENTER>"); 
     Console.ReadLine(); 
    } 

我想我有2個問題。

A)在將節點n上的ImportNode轉換爲outdoc後,我調用outdoc.AppendChild(n),它抱怨:「要插入的節點來自不同的文檔上下文。我不知道這是否是在ForEach循環中引用節點n的範圍問題 - 或者如果我以某種方式不正確地使用ImportNode()或AppendChild。 ImportNode()的第二個參數設置爲true,因爲我希望Animal的子元素(任意命名爲Quantity,Adjective和Name的3個字段)在目標文件中結束。 B)第二個問題是將Animal元素轉化爲outdoc。我得到''但我需要'',所以我可以將節點n放入其中。我認爲我的問題是我在做什麼:outdoc.AppendChild(rootnode);爲了顯示xml,我在做:outdoc.Save(Console.Out);我確實有將代碼保存()到輸出文件 - 這確實有效,只要我可以正確組裝outdoc。

還有一個類似的問題:Split XML in Multiple XML files,但我不明白的解決方案代碼呢。我想我很接近這種方法,並會感謝您提供的任何幫助。

我將使用XmlReader來完成同樣的任務,因爲我需要能夠處理大量的輸入文件,而且我知道XmlDocument會讀取整個內容並導致內存問題。

+0

在第二prolblem,我說:「我越來越----但需要----」應改爲:我越來越,但我需要。我需要一個名爲Animal的標籤,它帶有一個單獨的結束標籤(一個容器),而不僅僅是一個獨立的元素。另外 - 這個類似的問題有它的Java解決方案,我需要C#。 :) – 2012-08-11 05:17:45

回答

3

這是一個簡單的方法,似乎你在找什麼

public void test_xml_split() 
{ 
    XmlDocument doc = new XmlDocument(); 
    doc.Load("C:\\animals.xml"); 
    XmlDocument newXmlDoc = null; 

    foreach (XmlNode animalNode in doc.SelectNodes("//Animals/Animal")) 
    { 
     newXmlDoc = new XmlDocument(); 
     var targetNode = newXmlDoc.ImportNode(animalNode, true); 
     newXmlDoc.AppendChild(targetNode); 
     newXmlDoc.Save(Console.Out); 
     Console.WriteLine(); 
    } 
} 
+0

太棒了!這次真是萬分感謝。我必須做的唯一改變是檢索「序列」(中的id屬性),並將其從輸出文件 – 2012-08-11 18:18:52

+0

中刪除,您可以將其答覆並標記爲正確答案,如果您不介意:) – 2012-08-11 18:42:19

+0

我想知道我是否可以在Framework 2.0上使用「var targetnode」語句。 Docs表明它來自C#3.0(我認爲它是Framework v3)。 – 2012-08-12 02:03:20

0

這種做法似乎不使用「VAR targetnode」語句來工作。它通過ForEach循環中的outdoc的「Animal」元素創建一個名爲targetNode的XmlNode對象。我認爲我的原始代碼中存在的主要問題是:A)我錯誤地獲取了nodelist nl。和B)我不能「導入」節點n,我想是因爲它特別與文檔相關聯。必須將其創建爲其自己的節點。

先前提出的解決方案的問題是使用「var」關鍵字。我的程序必須假設2.0,並且v3.0版本。我喜歡羅傑斯的解決方案,因爲它很簡潔。對我而言 - 我想把每件事情都作爲一個單獨的陳述來做。

static void SplitXMLDocument() 
    { 
     string strFileName; 
     string strSeq; 
     XmlDocument doc = new XmlDocument();    // The input file 
     doc.Load("D:\\Rick\\Computer\\XML\\AnimalBatch.xml"); 
     XmlNodeList nl = doc.DocumentElement.SelectNodes("//Animals/Animal"); 

     foreach (XmlNode n in nl) 
     { 
      strSeq = n.Attributes["id"].Value;   // Animal nodes have an id attribute 

      XmlDocument outdoc = new XmlDocument();  // Create the outdoc xml document 
      XmlNode targetNode = outdoc.CreateElement("Animal"); // Create a separate node to hold the Animal element 

      targetNode = outdoc.ImportNode(n, true);  // Bring over that Animal 
      targetNode.Attributes.RemoveAll();   // Remove the id attribute in <Animal id="1001"> 

      outdoc.ImportNode(targetNode, true);   // place the node n into outdoc 
      outdoc.AppendChild(targetNode);    // AppendChild to make it stick 

      strFileName = "Animal_" + strSeq + ".xml";     
      outdoc.Save(Console.Out); Console.WriteLine(); 
      outdoc.Save("D:\\Rick\\Computer\\XML\\" + strFileName); 
      Console.WriteLine(); 
     } 
    }