重写大型 XML 文件 - 不包括某些节点
re-writing large XML Files - excluding certain node
我想重写一个大的 xml,去掉其中的一些节点。
我正在尝试使用 system.xml.xmlreader 逐行读取一个 XML 文件(100 MB,无法将其全部读入内存) - 努力寻找一种方法来读取其中的一部分,然后写入它们到一个单独的 xDocument,然后将该 xDocument 保存到磁盘。
我一直在想的是这样的:
using (XmlReader reader = XmlReader.Create(_xml_path))
{
using (XmlWriter writer = XmlWriter.Create(@"filteredxml.xml"))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name != "EL_TO_BE_REMOVED")
{
//writer.WriteNode(reader.ReadOuterXml());
}
}
}
}
}
但 reader.ReadOuterXml() 只是转到第一个元素并将其所有后代写入文件,而不让我过滤我希望忽略的元素。
在大文件和内存限制的情况下,您应该使用 SAX 而不是 DOM 进行解析:XMLReader 确实是 C# 的等价物。
这可能是一种基本方法,其中 XMLReader 用于输入,XMLWriter 用于输出,计数器用于删除名为 RemoveMe 的节点(及其所有内容)。
注意为每个相关元素克隆属性的内部循环。
using (XmlReader reader = XmlReader.Create(OriginalXml))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
using (XmlWriter writer = XmlWriter.Create(FilteredXml, ws))
{
int skip = 0;
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
skip += reader.Name.Equals(RemoveMe) ? 1 : 0;
if (skip == 0)
{
writer.WriteStartElement(reader.Name);
while (reader.MoveToNextAttribute())
writer.WriteAttributeString(reader.Name, reader.Value);
}
break;
case XmlNodeType.Text:
if (skip == 0)
{
writer.WriteString(reader.Value);
}
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
if (skip == 0)
{
writer.WriteProcessingInstruction(reader.Name, reader.Value);
}
break;
case XmlNodeType.Comment:
if (skip == 0)
{
writer.WriteComment(reader.Value);
}
break;
case XmlNodeType.EndElement:
if (skip == 0)
{
writer.WriteFullEndElement();
}
skip -= reader.Name.Equals(RemoveMe) ? 1 : 0;
if (skip < 0)
{
throw new Exception("wrong sequence");
}
break;
}
}
}
}
这听起来像是 XSLT 的工作。
XSL 转换 (RemoveElement.xslt):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="EL_TO_BE_REMOVED" />
</xsl:stylesheet>
执行转换的 C# 代码:
var transform = new XslCompiledTransform();
transform.Load("xslt/path/RemoveElement.xslt");
transform.Transform("input/xml/path/inputFile.xml", "output/xml/path/outputFile.xml");
我想重写一个大的 xml,去掉其中的一些节点。 我正在尝试使用 system.xml.xmlreader 逐行读取一个 XML 文件(100 MB,无法将其全部读入内存) - 努力寻找一种方法来读取其中的一部分,然后写入它们到一个单独的 xDocument,然后将该 xDocument 保存到磁盘。
我一直在想的是这样的:
using (XmlReader reader = XmlReader.Create(_xml_path))
{
using (XmlWriter writer = XmlWriter.Create(@"filteredxml.xml"))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name != "EL_TO_BE_REMOVED")
{
//writer.WriteNode(reader.ReadOuterXml());
}
}
}
}
}
但 reader.ReadOuterXml() 只是转到第一个元素并将其所有后代写入文件,而不让我过滤我希望忽略的元素。
在大文件和内存限制的情况下,您应该使用 SAX 而不是 DOM 进行解析:XMLReader 确实是 C# 的等价物。
这可能是一种基本方法,其中 XMLReader 用于输入,XMLWriter 用于输出,计数器用于删除名为 RemoveMe 的节点(及其所有内容)。
注意为每个相关元素克隆属性的内部循环。
using (XmlReader reader = XmlReader.Create(OriginalXml))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
using (XmlWriter writer = XmlWriter.Create(FilteredXml, ws))
{
int skip = 0;
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
skip += reader.Name.Equals(RemoveMe) ? 1 : 0;
if (skip == 0)
{
writer.WriteStartElement(reader.Name);
while (reader.MoveToNextAttribute())
writer.WriteAttributeString(reader.Name, reader.Value);
}
break;
case XmlNodeType.Text:
if (skip == 0)
{
writer.WriteString(reader.Value);
}
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
if (skip == 0)
{
writer.WriteProcessingInstruction(reader.Name, reader.Value);
}
break;
case XmlNodeType.Comment:
if (skip == 0)
{
writer.WriteComment(reader.Value);
}
break;
case XmlNodeType.EndElement:
if (skip == 0)
{
writer.WriteFullEndElement();
}
skip -= reader.Name.Equals(RemoveMe) ? 1 : 0;
if (skip < 0)
{
throw new Exception("wrong sequence");
}
break;
}
}
}
}
这听起来像是 XSLT 的工作。
XSL 转换 (RemoveElement.xslt):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="EL_TO_BE_REMOVED" />
</xsl:stylesheet>
执行转换的 C# 代码:
var transform = new XslCompiledTransform();
transform.Load("xslt/path/RemoveElement.xslt");
transform.Transform("input/xml/path/inputFile.xml", "output/xml/path/outputFile.xml");