【问题标题】:I need to split apart a large XML file to multiple output xmls, using XmlTextReader我需要使用 XmlTextReader 将大型 XML 文件拆分为多个输出 xml
【发布时间】:2012-08-27 05:57:42
【问题描述】:

我需要获取一个 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>
@ 987654337@
</Animals>

但实际上,其中没有 CR/LF 字符。实际的文本流如下所示:

<?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>

程序需要对重复的“Animal”进行拆分,生成3个文件,分别命名为:Animal_1001.xml、Animal_1002.xml、Animal_1003.xml

我之前使用 XmlDocument 对此有过疑问,该问题已得到解答。
参见:[使用 XmlDocument 将 XML 文件拆分为多个 xml][1]

这个问题是关于如何使用 XmlReader 来抓取元素并从中创建 XmlDocument 元素。


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>

这是有效的代码 - 但仅当输入文件中有换行符时:

    static void SplitXMLReader() 
    {
        string strFileName;
        string strSeq;

        XmlReader doc = XmlReader.Create("C:\\AnimalBatch.xml");

        while (doc.Read())
        {
            if (doc.Name=="Animal")
            {
                strSeq = doc.GetAttribute("id");

                XmlDocument outdoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                XmlElement rootNode = outdoc.CreateElement(doc.Name);

                rootNode.InnerXml = doc.ReadInnerXml();
                outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
                outdoc.AppendChild(rootNode);

                strFileName = "Animal_" + strSeq + ".xml";
                outdoc.Save("C:\\" + strFileName);
            }
        }
    }

当此程序在每个元素后都有回车符的“AnimalBatch.xml”副本上运行时 - 它可以工作,并根据需要创建 Animal_xxxx.xml 文件。当 AnimalBatch.xml 看起来像未格式化的文本流时 - 它获取第一个 Animal - 并且可以获得它的 ID 1001 并写入输出文件 ok。它能够读取后续的 Animal 元素但不能获取“id”属性 - 并最终写入名为“Animal_.xml”的输出文件 - 因为它试图从属性中读取的 strSeq 变量显然是 null 或空白。最后,第二个文件只包含这个:

<?xml version="1.0" encoding="utf-8"?>
<Animal />

这让我相信 XmlReader,至少在 doc.Read() 方法的范围内,(doc.Name=="Animal") 语句或后来的“strSeq = doc.GetAttribute("id" ); " - 如果<Animal id="1002"> 标记后有 CR/LF,则工作方式不同。

我想我真正的问题是 - 什么时候 doc.GetAttribute("id");文档中的光标在哪里?为什么它不能得到“1001”之后的那些 - 这确实有效?

John 说 XML 不关心格式 - 我也一直这么认为 - 但这令人困惑。另外 - 对于我的应用程序,我可以获得 XML 的唯一方法是未格式化,因为我通过 SSIS 退出 SQL,它是文本流,而不是 XML 对象。

【问题讨论】:

  • 仅供参考,请勿使用new XmlTextReader。请改用XmlReader.Create。
  • 约翰 - 我得给你起立鼓掌。您观察到使用 XmlReader 而不是 XmlTextReader 是解决方案。文本阅读器的问题显然与它无法识别随后的“动物”元素有关(它会得到第一个 - 但当我试图获取属性“ID”时 - 它只找到第一个 -好吧 - 我手上一团糟。我将发布现在有效的代码。
  • John - 我发现我的输入文件没有 CR/LF 的“格式”,如我的示例中所示。这是否意味着我必须使用 xmlTextReader?我已经使用它取得了一定程度的成功(即我可以获得外部 xml - 只是无法提取 ID 属性)。也许我需要在一个单独的问题中指定这一点。
  • 格式化与 XML 无关。

标签: c# xml split large-files xmltextreader


【解决方案1】:

首先,我没有看到你在任何地方为outdoc 分配任何东西......我想你想用当前节点数据填充它,然后保存它?另外,我会创建一个XmlDocument 对象,然后在循环中清除/填充它,在循环中创建新对象几千次并不是一个好主意...

还要注意XmlReader 一次移动一个元素。所以你的代码 atm 会:

  1. 致电XmlRead(),不会陷入任何情况(首先阅读?xml 声明)
  2. 调用XmlRead()一次,掉进箱子里,移动到id属性写空文件。
  3. 调用XmlRead()10次 \,跳过所有内容直到下一个Animal元素。

从<Animal> 标签内部获取数据的一种解决方案类似于This example on msdn。

其次是想出更方便的方法,比如ReadInnerXml方法和ReadToFollowing。 另外,看看GetAttribute method。

我的程序是:

  1. string toFile = "";
  2. 读取文件直到<Animal>标签。
  3. GetAttribute("id");
  4. toFile = ReadInnerXml();
  5. 将toFile 写入文件;)
  6. doc.ReadToFollowing("Animal");

可能有一些小的调整,因为我没有检查我用编译器编写的内容......

【讨论】:

    【解决方案2】:

    您需要在 outdoc 上创建根节点。使用此代码:

        static void SplitXMLTextReader()
        {
    
            string strFileName;
            string strSeq = "0";
    
            XmlTextReader doc = new XmlTextReader(("C:\\AnimalBatch.xml"));
            doc.WhitespaceHandling = WhitespaceHandling.None;
    
            while (doc.Read())
            {
                switch (doc.Name)
                {
                    case "Animal":
                        XmlDocument outdoc = new XmlDocument();
                       XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                           XmlElement rootNode = outdoc.CreateElement(doc.Name);
                        rootNode.InnerXml = doc.ReadInnerXml();
                        outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
                        outdoc.AppendChild(rootNode);
    
    
                        doc.MoveToFirstAttribute();
                        if (string.Compare(doc.Name, "id", true) == 0)
                        {
                            strSeq = doc.Value;
                        }
                        strFileName = "Animal_" + strSeq + ".xml";
                        outdoc.Save("C:\\" + strFileName);
                        break;
                }
            }
    
        }
    

    【讨论】:

    • 这个解决方案很接近,但有一个错误:我得到两个名为 Animal_0002.xml 和 Animal_003.xml 的输出 xml 文件。 Animal_0002.xml 有一个完整的输出文件,但包含第一个动物(一只红公鸡)的内容,Animal_0002.xml 只有一个空标签 ,但没有有效负载。我在想,获取 id 的程序部分(以“doc.MoveToFirstAttribute()”开头的部分) - 可能需要从 outdoc 中获取其信息 - 在它被附加到 outdoc 之后。但是 - 你的代码非常接近。我明白了您如何在 doc.Read() 循环中创建 outdoc XmlDocuments。
    【解决方案3】:
    static void SplitXMLReader()
    {
        string strFileName;
        string strSeq;
    
        XmlReader doc = XmlReader.Create("C:\\AnimalBatch.xml");
    
        while (doc.Read())
        {
            if (doc.Name=="Animal")
            {
                strSeq = doc.GetAttribute("id");
    
                XmlDocument outdoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = outdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                XmlElement rootNode = outdoc.CreateElement(doc.Name);
    
                rootNode.InnerXml = doc.ReadInnerXml();
                outdoc.InsertBefore(xmlDeclaration, outdoc.DocumentElement);
                outdoc.AppendChild(rootNode);
    
                strFileName = "Animal_" + strSeq + ".xml";
                outdoc.Save("C:\\" + strFileName);
            }
        }
    }
    

    【讨论】:

    • OMG - 我发现我的“批处理”xml 文件是一个文本流 - 并且没有我在“AnimalBatch.xml”示例文件中指定的 CRLF。当 节点之后有 CRLF 时,上述“解决方案”有效 - 但如果没有,则无法使用 XmlReader。我重新开始使用 XmlTextReader。呸。
    • 在 XML 输入文件中没有换行符时如何执行此操作的答案在另一个问题下:stackoverflow.com/questions/12188383/…
    猜你喜欢
    • 1970-01-01
    • 2019-10-21
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多