2012-08-11 90 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(); 
     } 
    }