0

我需要获取一个 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>
</Animal>
</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 对象。

4

3 回答 3

0

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

还要注意XmlReader一次移动一个元素。所以你的代码自动取款机将:

  1. 打电话XmlRead()而不是陷入任何情况(它会阅读第一个?xml声明)
  2. 调用XmlRead()一次,陷入案例,移动到id属性并写入空文件。
  3. 调用XmlRead() 10 次\,跳过所有内容直到下一个Animal元素。

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

其次是想出更方便的方法,例如带有ReadToFollowing的ReadInnerXml方法。另外,看看GetAttribute 方法

我的程序是:

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

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

于 2012-08-27T07:03:11.070 回答
0
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);
        }
    }
}
于 2012-08-27T21:00:40.570 回答
0

您需要在 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;
            }
        }

    }
于 2012-08-27T11:06:35.113 回答