使用 XMLReader 解析大 XML 文件

Posted

技术标签:

【中文标题】使用 XMLReader 解析大 XML 文件【英文标题】:Parse Big XML file using XMLReader 【发布时间】:2020-08-19 18:17:06 【问题描述】:

我有一个非常大的 xml 文件,格式如下

<ABC>
  <NAMEDETAILS></NAMEDETAILS>
  <PRODUCT>
    <PRODUCTDETAILS>
      <ProductName>
         <name>Car</Name>
         <name>lorry<name>
         <name>Car<name>
      </ProductName>
    </PRODUCTDETAILS>
    <PRODUCTDETAILS>
      <ProductName>
         <name>van</Name>
         <name>cycle</Name>
         <name>bus</Name>
      </ProductName>
    </PRODUCTDETAILS>
    <PRODUCTDETAILS>
      <ProductName>
         <name>car</Name>
         <name>cycle</Name>
         <name>bus</Name>
      </ProductName>
    </PRODUCTDETAILS>
  <PRODUCT>    
</ABC>

我想检索名称标签值为“car”的 PRODUCTDETAILS 数据,并将其保存在一个新的 xml 文件中。我正在使用 XMLReader,但我一直在前进。有人可以帮助我。下面是c#代码

XMLReader xmlReader = XMLReader.Create(@"\\Drive\xmlfile.xml")
while (xmlReader.Read())

  If (xmlReader.NodeType == XMLNodeType.Element) && (xmlReader.Name == "PRODUCTDETAILS")
  
    xmlReader.ReadtoDescendant("ProductName")
  

【问题讨论】:

【参考方案1】:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace ConApp1

    class Program
    
        static void Main()
        
            using (var xmlWriter = XmlWriter.Create("result.xml"))
            using (var xmlReader = XmlReader.Create("test.xml"))
            
                xmlWriter.WriteStartElement("PRODUCT");

                while (xmlReader.ReadToFollowing("PRODUCTDETAILS"))
                
                    using (var nodeReader = xmlReader.ReadSubtree())
                    
                        nodeReader.MoveToContent();

                        var elem = (XElement)XNode.ReadFrom(nodeReader);

                        var name = elem.Descendants("name").First().Value;

                        if (name.Equals("car", StringComparison.OrdinalIgnoreCase))
                        
                            elem.WriteTo(xmlWriter);
                        
                    
                
            
        
    

既然你说文件很大,那么读写都应该使用流式工具来完成。 XmlWriter 用于写作。这保证了低内存消耗并且不会出现OutOfMemoryException

【讨论】:

【参考方案2】:

尝试以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1

    class Program
    
        const string INPUT_FILENAME = @"c:\temp\test.xml";
        const string OUTPUT_FILENAME = @"c:\temp\test1.xml";
        static void Main(string[] args)
        
            XmlReader reader = XmlReader.Create(INPUT_FILENAME);

            string header = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Cars></Cars>";
            XDocument doc = XDocument.Parse(header);
            XElement cars = doc.Root;

            while (!reader.EOF)
            
                if (reader.Name != "PRODUCTDETAILS")
                
                    reader.ReadToFollowing("PRODUCTDETAILS");
                
                if (!reader.EOF)
                
                    XElement product = (XElement)XElement.ReadFrom(reader);
                    if(product.Descendants("name").Any(x => ((string)x).Trim() == "Car"))
                    
                        cars.Add(product);
                    

                
            
            doc.Save(OUTPUT_FILENAME);
        
    


【讨论】:

我可以得到 xelement。但是每个 ProductName 都有很多名称标签。如果我使用 FirstOrDefault() 我只会得到第一个值。我想知道 ProductName 中的至少一个名称标签是否具有值“car”。如果是,我希望将特定的 ProductDetails 数据作为一个整体放在一个单独的 xml 文件中@jdweng​​span>

以上是关于使用 XMLReader 解析大 XML 文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 XMLreader 读取和解析大型 XML 文件。空值问题

使用XDocument.Load(xmlreader)方法?

如何在 PowerShell 中使用 XmlReader 流式传输大/巨大的 XML 文件?

在 php 中解析非常大的 XML 文件

PHP XMLReader 解析行 2 次

2 怎样解析XML文件或字符串