C# 编辑一个大的XML文件
我有一个3GB的XML文件。我需要将节点作为另一个节点的子节点移动。以C# 编辑一个大的XML文件,c#,xml,C#,Xml,我有一个3GB的XML文件。我需要将节点作为另一个节点的子节点移动。以XmlDocument的形式加载大文件效率不高。我知道XmlReader是另一种方法,但不确定它在我的场景中如何工作,以及我应该使用哪些其他类来实现这一点 我需要将所有alias节点移动到其相关的customer>name节点 <customer> <name><first>Robert</first></name> <alias>Rob</alia
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属性来定位每个记录。此解决方案可能比较慢,但可以避免内存错误。