重写大型XML文件-不包括某些节点

本文关键字:节点 不包括 大型 XML 文件 重写 | 更新日期: 2023-09-27 18:06:29

我想重新编写一个大型xml,而不需要它的一些节点。我试图读取一个XML文件(100 mb,不能全部读到内存)一行一行使用system.xml.xmlreader -努力找到一种方法来读取它的一部分,把它们写下来一个单独的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()只是转到第一个元素,并将其所有后代元素写入文件,而不允许我过滤希望忽略的元素。

重写大型XML文件-不包括某些节点

在大文件和内存限制的情况下,您应该使用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 Transform (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");