将XML文档拆分,从重复元素中创建多个输出文件

4

我需要从一个XML文件中提取重复节点并创建多个输出XML文件。源文件"AnimalBatch.xml"的格式如下:

One Red Rooster Two Stubborn Donkeys Three Blind Mice 该程序需要拆分重复的“Animal”并生成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>一个</Quantity>
<Adjective>红色的</Adjective>
<Name>公鸡</Name>
</Animal>


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


Animal_1003.xml>
<?xml version="1.0" encoding="utf-8"?>
<Animal>
<Quantity>三只</Quantity>
<Adjective>盲</Adjective>
<Name>老鼠</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();
    }

我认为我有两个问题。

A) 在将节点n导入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即可正常工作。

这里有一个类似的问题: 将XML拆分为多个XML文件, 但我还不明白解决方案代码。 我认为我在这个方法上已经很接近了,并且将会感谢任何您可以提供的帮助。

我将使用XmlReader执行相同的任务,因为我需要能够处理大型输入文件,并且我知道XmlDocument会一次性读取整个文件,可能会导致内存问题。


在第二个问题中,当我说“我得到了----但需要----”时,应该这样写:我得到了<Animal/>,但我需要<Animal></Animal>。我需要一个名为Animal的标签,它有一个单独的闭合标签(一个容器),而不仅仅是一个独立的元素。此外 - 类似于这个问题的问题在Java中已经有了解决方案,而我需要C#。 :) - Rick Bellows
2个回答

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();
    }
}

太好了!谢谢你的帮助。我只需要做一个小改动,就是获取“Sequence”(在<Animal id="1001">中的id属性),并将其从输出文件中删除。 - Rick Bellows
如果您不介意,请点赞并标记答案为正确。 :) - Konstantin Chernov
我在想是否可以在 Framework 2.0 上使用“var targetnode”语句。文档表明它是在 C# 3.0 中引入的(我假设这是 Framework v3)。 - Rick Bellows
确实,var是在C# v3中引入的语法糖,我忽略了你对v2的要求。 - Konstantin Chernov

1

这种方法似乎可以在不使用“var targetnode”语句的情况下工作。它从ForEach循环中的outdoc的“Animal”元素创建一个名为targetNode的XmlNode对象。我认为原始代码中存在问题的主要因素是:A)我错误地获取了nodelist nl。B)我无法“导入”节点n,我认为是因为它与doc具体相关联。它必须被创建为它自己的节点。

以前提出的解决方案的问题在于使用了“var”关键字。我的程序必须假定2.0,并带有v3.0。我喜欢Rogers的解决方案,因为它简洁明了。对于我来说-我想要将每个事情作为单独的语句执行。

    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();
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接