【问题标题】:Split XML document apart creating multiple output files from repeating elements拆分 XML 文档,从重复元素创建多个输出文件
【发布时间】:2012-08-11 05:12:44
【问题描述】:

我需要获取一个 XML 文件并从输入文件的重复节点创建多个输出 xml 文件。源文件“AnimalBatch.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>
@ 987654338@
</Animals>

程序需要对重复的“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>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();
    }

我认为我有两个问题。

A) 在将节点 n 上的 ImportNode 导入 o​​utdoc 后,我调用 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);我确实有将 save() 保存到输出文件的代码 - 只要我能正确组装 outdoc,它就可以工作。

Split XML in Multiple XML files也有类似的问题,但是我还不明白解决方案的代码。我想我已经非常接近这种方法了,如果你能提供任何帮助,我将不胜感激。

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

【问题讨论】:

  • 在我说“我得到 ---- 但需要 ----”的第二个问题中应该读作:我得到 但我需要 。我需要一个名为 Animal 的标签,它带有一个单独的结束标签(一个容器),而不仅仅是一个独立的元素。另外-与此类似的问题在Java中有其解决方案,我需要C#。 :)

标签: c# xml .net-2.0 xmldocument


【解决方案1】:

这是一个看似你正在寻找的简单方法

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

【讨论】:

  • 太棒了!这次真是万分感谢。我必须做的唯一更改是检索“序列”( 中的 id 属性),并将其从输出文件中删除
  • 如果您不介意,您可以投票并将答案标记为正确 :)
  • 我想知道是否可以在 Framework 2.0 上使用“var targetnode”语句。文档表明它出现在 C# 3.0(我假设是 Framework v3)。
  • 确实,var 是 C# v3 中引入的语法糖,我忽略了你的 v2 要求
【解决方案2】:

这种方法似乎可以在不使用“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();
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 2020-04-25
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    相关资源
    最近更新 更多