【问题标题】:New XML file from another large XML file, changing data inside with unknown elements来自另一个大型 XML 文件的新 XML 文件,使用未知元素更改内部数据
【发布时间】:2016-02-19 01:08:02
【问题描述】:

我有一个非常大 (~1GB) 的 XML 文件。我需要解析它,找到特定节点,更改这些节点中的数据,然后将其全部写入一个新的 XML 文件。这就是问题所在——有很多我不关心的元素——我什至不知道它们都是什么——但它们也需要被复制。

This SO post 建议我使用 XmlReader,这样我就不必将整个输入文件加载到内存中。该问题有this 答案,建议使用ReadToDescendant 方法。这几乎可以满足我的需要,但问题是我在“读取”的节点之前丢失了所有 XML。不知何故,我需要将我刚刚读过的所有内容复制到新文件中。我不在乎那里有什么,只需要逐字复制。

This SO 帖子可以工作(还有其他几个类似的帖子),除了它使用XmlDocument,如果我没记错的话,它将首先将整个内容加载到内存中。虽然这对于小文件来说很好,但我想在这里避免这种情况。

对于您的视觉类型,这是我想要做的一个想法:

<root>
 <SomeNodeUndefinedAtDesignTime>
    <ThisNodeHasSubNodes>
        <WhichHasSubNodes_Etc/>
    </ThisNodeHasSubNodes>
 </SomeNodeUndefinedAtDesignTime>
 <AnotherUndefinedNode>
    <!--Similar to the first, who knows what all is in here-->
 </AnotherUndefinedNode>
 <!-- There may be dozens or even hundreds of these -->
 <ANodeIAmInterestedIn>
    Old data to be replaced
 </ANodeIAmInterestedIn>
 <ANodeIAmInterestedIn>
    More data to be replaced
 </ANodeIAmInterestedIn>
 <YetAnotherUndefinedNode>
    <!-- stuff -->
 </YetAnotherUndefinedNode>
</root>

我想接受那个输入然后输出这个:

<root>
 <SomeNodeUndefinedAtDesignTime>
    <ThisNodeHasSubNodes>
        <WhichHasSubNodes_Etc/>
    </ThisNodeHasSubNodes>
 </SomeNodeUndefinedAtDesignTime>
 <AnotherUndefinedNode>
    <!--Similar to the first, who knows what all is in here-->
 </AnotherUndefinedNode>
 <!-- There may be dozens or even hundreds of these -->
 <ANodeIAmInterestedIn>
    Here is my new data
 </ANodeIAmInterestedIn>
 <ANodeIAmInterestedIn>
    Here is more new data
 </ANodeIAmInterestedIn>
 <YetAnotherUndefinedNode>

    <!-- stuff -->
 </YetAnotherUndefinedNode>
</root>

有没有办法

  1. 将文件作为流读取,这样我就不必一次将整个内容加载到内存中
  2. 复制设计时未定义的元素
  3. 更改特定元素中的数据
  4. 将结果写入新文件

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    您可以使用 XmlReaderXmlWriter 创建一个方法,这将完全满足您的需求。

    public void CopyTo(XmlReader reader, XmlWriter writer, 
        Dictionary<string, string> replacements)
    {
        var currentElementName = "";
        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    currentElementName = reader.Name;
                    writer.WriteStartElement(reader.Name);
    
                    //Copy all attributes verbatim
                    if (reader.HasAttributes)
                       writer.WriteAttributes(reader, true);
    
                    //Handle empty elements by telling the writer to close right away
                    if (reader.IsEmptyElement)
                       writer.WriteEndElement();
                    break;
                case XmlNodeType.EndElement:
                    currentElementName = "";
                    writer.WriteEndElement();
                    break;
                case XmlNodeType.Text:
                    if (replacements.ContainsKey(currentElementName))
                        writer.WriteString(replacements[currentElementName]);
                    else
                        writer.WriteString(reader.Value);
                    break;
                case XmlNodeType.Whitespace:
                    writer.WriteWhitespace(reader.Value);
                    break;
               //Other cases. Attributes, comments etc.
            }
            writer.Flush();
        }
    }
    

    这是一个简单的示例,它不会处理属性和其他一些人员,但它可以很好地处理元素。
    它将复制 xml 结构和所有元素,并将 innerText 替换为已知元素。

    用法:

    var xmlReader = XmlReader.Create(File.OpenRead("inputFilePath"));
    var xmlWriter = XmlWriter.Create(File.OpenWrite("outputFilePath"));
    var replacements = new Dictionary<string, string> { ... };
    CopyTo(xmlReader, xmlWriter, replacements);
    

    此外,如果您想在读取大型元素时做一些有用的事情,您可以使用 async 版本的 XmlReader 方法。

    【讨论】:

    • 我稍微调整了您的代码示例,现在它可以按照我想要的方式进行所有复制。感谢您在正确方向上的大力推动!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 2020-07-31
    • 2021-10-08
    • 2021-01-01
    • 1970-01-01
    • 2021-03-13
    相关资源
    最近更新 更多