C# 编辑一个大的XML文件

C# 编辑一个大的XML文件,c#,xml,C#,Xml,我有一个3GB的XML文件。我需要将节点作为另一个节点的子节点移动。以XmlDocument的形式加载大文件效率不高。我知道XmlReader是另一种方法,但不确定它在我的场景中如何工作,以及我应该使用哪些其他类来实现这一点 我需要将所有alias节点移动到其相关的customer>name节点 <customer> <name><first>Robert</first></name> <alias>Rob</alia

我有一个3GB的XML文件。我需要将节点作为另一个节点的子节点移动。以
XmlDocument
的形式加载大文件效率不高。我知道
XmlReader
是另一种方法,但不确定它在我的场景中如何工作,以及我应该使用哪些其他类来实现这一点

我需要将所有alias节点移动到其相关的customer>name节点

<customer>
<name><first>Robert</first></name>
<alias>Rob</alias>
</customer>

罗伯特
抢劫

您可以做的是从Mark Fussell的文章中将
XmlReader
流式传输到
XmlWriter
的基本逻辑,将您的3GB文件转换为修改后的文件,其中

以该答案为基础,从中获取类
XmlReaderExtensions
XmlWriterExtensions
XmlStreamingEditorBase
XmlStreamingEditor
,并从中获取子类
XmlStreamingEditor
,以创建
customeralIASSmleditor
,如下所示:

class CustomerAliasXmlEditor : XmlStreamingEditor
{
    // Confirm that the <customer> element is not in any namespace.
    static readonly XNamespace customerNamespace = ""; 

    public static void TransformFromTo(string fromFilePath, XmlReaderSettings readerSettings, string toFilePath, XmlWriterSettings writerSettings)
    {
        using (var xmlReader = XmlReader.Create(fromFilePath, readerSettings))
        using (var xmlWriter = XmlWriter.Create(toFilePath, writerSettings))
        {
            new CustomerAliasXmlEditor(xmlReader, xmlWriter).Process();
        }
    }

    public CustomerAliasXmlEditor(XmlReader reader, XmlWriter writer)
        : base(reader, writer, ShouldTransform, Transform)
    {
    }

    static bool ShouldTransform(XmlReader reader)
    {
        return reader.GetElementName() == customerNamespace + "customer";
    }

    static void Transform(XmlReader from, XmlWriter to)
    {
        var customer = XElement.Load(from);
        var alias = customer.Element(customerNamespace + "alias");
        if (alias != null)
        {
            var name = customer.Element(customerNamespace + "name");
            if (name == null)
            {
                name = new XElement(customerNamespace + "name");
                customer.Add(name);
            }
            alias.Remove();
            name.Add(alias);
        }
        customer.WriteTo(to);
    }
}
示例工作显示XML

<Root>
<Item>
<SubItem>
<customer>
<name><first>Robert</first></name>
<alias>Rob</alias>
</customer>
</SubItem>
</Item>
<Item>
</Root>

罗伯特
抢劫
转化为

<Root>
  <Item>
    <SubItem>
      <customer>
        <name>
          <first>Robert</first>
          <alias>Rob</alias>
        </name>
      </customer>
    </SubItem>
  </Item>
  <Item>
</Root>

罗伯特
抢劫

您可以做的是从Mark Fussell的文章中将
XmlReader
流式传输到
XmlWriter
的基本逻辑,将您的3GB文件转换为修改后的文件,其中

以该答案为基础,从中获取类
XmlReaderExtensions
XmlWriterExtensions
XmlStreamingEditorBase
XmlStreamingEditor
,并从中获取子类
XmlStreamingEditor
,以创建
customeralIASSmleditor
,如下所示:

class CustomerAliasXmlEditor : XmlStreamingEditor
{
    // Confirm that the <customer> element is not in any namespace.
    static readonly XNamespace customerNamespace = ""; 

    public static void TransformFromTo(string fromFilePath, XmlReaderSettings readerSettings, string toFilePath, XmlWriterSettings writerSettings)
    {
        using (var xmlReader = XmlReader.Create(fromFilePath, readerSettings))
        using (var xmlWriter = XmlWriter.Create(toFilePath, writerSettings))
        {
            new CustomerAliasXmlEditor(xmlReader, xmlWriter).Process();
        }
    }

    public CustomerAliasXmlEditor(XmlReader reader, XmlWriter writer)
        : base(reader, writer, ShouldTransform, Transform)
    {
    }

    static bool ShouldTransform(XmlReader reader)
    {
        return reader.GetElementName() == customerNamespace + "customer";
    }

    static void Transform(XmlReader from, XmlWriter to)
    {
        var customer = XElement.Load(from);
        var alias = customer.Element(customerNamespace + "alias");
        if (alias != null)
        {
            var name = customer.Element(customerNamespace + "name");
            if (name == null)
            {
                name = new XElement(customerNamespace + "name");
                customer.Add(name);
            }
            alias.Remove();
            name.Add(alias);
        }
        customer.WriteTo(to);
    }
}
示例工作显示XML

<Root>
<Item>
<SubItem>
<customer>
<name><first>Robert</first></name>
<alias>Rob</alias>
</customer>
</SubItem>
</Item>
<Item>
</Root>

罗伯特
抢劫
转化为

<Root>
  <Item>
    <SubItem>
      <customer>
        <name>
          <first>Robert</first>
          <alias>Rob</alias>
        </name>
      </customer>
    </SubItem>
  </Item>
  <Item>
</Root>

罗伯特
抢劫

我不太清楚您想要执行什么样的转换,但假设@dbc的猜测是正确的,您可以使用如下的流式XSLT 3.0处理器:

<xsl:transform version="3.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:mode streamable="yes" on-no-match="shallow-copy">

<xsl:template match="customer">
  <xsl:apply-templates select="copy-of(.)" mode="local"/>
</xsl:template>

<xsl:mode name="local" streamable="no" on-no-match="shallow-copy"/>

<xsl:template match="name" mode="local">
  <name>
    <xsl:apply-templates mode="local"/>
    <xsl:copy-of select="../alias"/>
  </name>
</xsl:template>

<xsl:template match="alias" mode="local"/>

</xsl:transform>


这里发生的事情是,所有内容都以纯流模式(标签对标签)进行复制,直到我们遇到客户元素。当我们遇到一个客户元素时,我们会制作该元素的内存副本,并使用传统的非流式转换对其进行本地转换。因此,所需的内存量刚好足以容纳最大的客户元素。

我不太清楚您想要执行什么样的转换,但假设@dbc的猜测是正确的,您可以使用如下流式XSLT 3.0处理器:

<xsl:transform version="3.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:mode streamable="yes" on-no-match="shallow-copy">

<xsl:template match="customer">
  <xsl:apply-templates select="copy-of(.)" mode="local"/>
</xsl:template>

<xsl:mode name="local" streamable="no" on-no-match="shallow-copy"/>

<xsl:template match="name" mode="local">
  <name>
    <xsl:apply-templates mode="local"/>
    <xsl:copy-of select="../alias"/>
  </name>
</xsl:template>

<xsl:template match="alias" mode="local"/>

</xsl:transform>


这里发生的事情是,所有内容都以纯流模式(标签对标签)进行复制,直到我们遇到客户元素。当我们遇到一个客户元素时,我们会制作该元素的内存副本,并使用传统的非流式转换对其进行本地转换。因此,所需的内存量刚好足以容纳最大的customer元素。

3g字节的XML文件?也许将此文件拆分为较小的文件是一个很好的第一步。64位应用程序是否允许您使用
XDocument
读取XML?可能是这样的吗?一个3千兆字节的XML文件?也许将此文件拆分为较小的文件是一个很好的第一步。64位应用程序是否允许您使用
XDocument
读取XML?可能是这样的吗?我非常喜欢你的解决方案,但我认为它对xml的结构做了一些假设,不认为它能处理大型文件。我们应该从op中获取结构示例。怀疑xml文件包含一个节点。因此解决方案是创建一个包含的写xml文件。对该文件进行两次分析。第一次通过创建一组按用户名列出元素。第二步写入组。文件太大,可能会使用XmlReader base stream的position属性来定位每个记录。此解决方案可能速度较慢,但会避免内存错误。我非常喜欢您的解决方案,但我认为它对xml的结构做了一些假设,不认为它能处理大型文件。我们应该从op中获取结构示例。怀疑xml文件包含一个节点。因此解决方案是创建一个包含的写xml文件。对该文件进行两次分析。第一次通过创建一组按用户名列出元素。第二步写入组。文件太大,可能需要使用XmlReader基流的position属性来定位每个记录。此解决方案可能比较慢,但可以避免内存错误。