我有一个3GB的XML文件。我需要将节点作为另一个节点的子节点移动。将大文件加载为XmlDocument
效率不高。我看到XmlReader
是另一种方法,但不确定它在我的场景中究竟是如何工作的,以及我应该使用哪些其他类来实现这一点。
我需要将所有别名节点移动到其相关客户>名称节点。
<customer>
<name><first>Robert</first></name>
<alias>Rob</alias>
</customer>
答案 0 :(得分:1)
我真的不明白你想要执行什么转换,但假设@ 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>
这里发生的事情是,在我们点击客户元素之前,所有内容都会以纯流模式(标记标记)进行复制。当我们遇到客户元素时,我们制作元素的内存副本,并使用传统的非流转换在本地转换它。因此,所需的内存量足以容纳最大的客户元素。
答案 1 :(得分:0)
您可以采取的措施是将来自Mark Fussell的文章Combining the XmlReader and XmlWriter classes for simple streaming transformations的XmlReader
流式传输到XmlWriter
的基本逻辑,将您的3GB文件转换为修改后的文件其中<alias>
个节点已重定位到<name>
个节点。 this answer至 Automating replacing tables from external files 中提供了使用此类流式转换的示例。
以该答案为基础,从中抓取课程XmlReaderExtensions
,XmlWriterExtensions
,XmlStreamingEditorBase
和XmlStreamingEditor
以及XmlStreamingEditor
子类以创建{{1}如下:
CustomerAliasXmlEditor
然后,如果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);
}
}
是您当前3GB XML文件的名称,而fromFileName
是要将转换后的XML输出到的文件的名称,则可以执行以下操作:
toFileName
示例工作.Net fiddle显示XML
var readerSettings = new XmlReaderSettings { IgnoreWhitespace = true };
var writerSettings = new XmlWriterSettings { Indent = false}; // Or true if you prefer.
CustomerAliasXmlEditor.TransformFromTo(fromFileName, readerSettings, toFileName, writerSettings);
转换为
<Root>
<Item>
<SubItem>
<customer>
<name><first>Robert</first></name>
<alias>Rob</alias>
</customer>
</SubItem>
</Item>
<Item>
</Root>