C#按路徑流式遍歷XML節(jié)點(diǎn)的實(shí)用方法
引言
在處理大型 XML 文檔時(shí),傳統(tǒng)的 XDocument.Load 會一次性將整個(gè)文檔加載到內(nèi)存中,對于大文件非常消耗資源。尤其在只需要部分節(jié)點(diǎn)的場景下,這種方式既浪費(fèi)內(nèi)存,又影響性能。
本文將分享一個(gè)按路徑流式遍歷 XML 節(jié)點(diǎn)的實(shí)用方法,支持深層嵌套路徑,并保持流式解析,內(nèi)存占用低,非常適合大文件處理。
方法原理
流式解析
使用 XmlReader 逐節(jié)點(diǎn)讀取 XML 文檔,而不是一次性加載整個(gè)文檔,節(jié)省內(nèi)存。
按路徑過濾節(jié)點(diǎn)
用戶只需提供路徑,例如 "set/fields/field",方法會按照路徑遞歸查找目標(biāo)元素。
XNode.ReadFrom 創(chuàng)建完整 XElement
當(dāng)讀到目標(biāo)元素時(shí),使用 XNode.ReadFrom(reader) 構(gòu)建 XElement,包括子節(jié)點(diǎn)及結(jié)束標(biāo)簽,并將 XmlReader 定位到下一個(gè)兄弟節(jié)點(diǎn),保證流式遍歷不中斷。
遞歸獲取子節(jié)點(diǎn)
對于多級路徑,使用遞歸方法從 XElement 訪問子節(jié)點(diǎn)
使用示例
假設(shè)有如下 XML:
<set>
<fields>
<field>
<fieldname>rq</fieldname>
<datatype>字符</datatype>
</field>
<field>
<fieldname>djbh</fieldname>
<datatype>字符</datatype>
</field>
</fields>
</set>
調(diào)用:
string xmlstr = File.ReadAllText("example.xml");
var fields = XmlStreamHelper.StreamElements(xmlstr, "set/fields/field");
Console.WriteLine("字段數(shù)量:" + fields.Count());
foreach (var f in fields)
{
Console.WriteLine(f.Element("fieldname")?.Value);
}
輸出:
字段數(shù)量:2 rq djbh
優(yōu)點(diǎn)總結(jié)
- 內(nèi)存占用低:大 XML 文件也能按需遍歷,不會一次性加載整個(gè)文檔。
- 路徑靈活:支持任意深度路徑,按需獲取節(jié)點(diǎn)。
- 避免 ReadSubtree 陷阱:使用
XNode.ReadFrom與遞歸子節(jié)點(diǎn),狀態(tài)管理清晰。 - 延遲執(zhí)行:返回
IEnumerable<XElement>,可以直接在foreach中流式消費(fèi)。
擴(kuò)展思路
- 可以在路徑中增加通配符
*或//,支持 XPath-like 查找。 - 可以結(jié)合
yield return,實(shí)現(xiàn)大文件邊解析邊處理,適合數(shù)據(jù)清洗、日志分析、報(bào)表導(dǎo)出等場景。
完整代碼
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
public static class XmlStreamHelper
{
/// <summary>
/// 按路徑流式遍歷 XML 節(jié)點(diǎn),路徑用 / 分隔
/// </summary>
/// <param name="xmlstr">XML 字符串</param>
/// <param name="xpath">節(jié)點(diǎn)路徑,例如 "set/fields/field"</param>
public static IEnumerable<XElement> StreamElements(string xmlstr, string xpath)
{
if (string.IsNullOrWhiteSpace(xmlstr) || string.IsNullOrWhiteSpace(xpath))
yield break;
var nodes = xpath.Split('/');
using var reader = XmlReader.Create(new StringReader(xmlstr), new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true });
reader.MoveToContent();
if (nodes.Length == 1)
{
if (XNode.ReadFrom(reader) is XElement el)
{
foreach (var e in el.Elements(xpath))
{
yield return e;
}
}
}
else
{
while (reader.Read())
{
if (reader.NodeType != XmlNodeType.Element) continue;
if (reader.Name == nodes[0] && XNode.ReadFrom(reader) is XElement el)
{
foreach (var child in GetElementsRecursive(el, nodes, 1))
yield return child;
}
}
}
}
/// <summary>
/// 遞歸獲取子節(jié)點(diǎn)
/// </summary>
private static IEnumerable<XElement> GetElementsRecursive(XElement el, string[] nodes, int index)
{
if (index == nodes.Length - 1)
return el.Elements(nodes[index]);
var sub = el.Element(nodes[index]);
return sub == null ? Enumerable.Empty<XElement>() : GetElementsRecursive(sub, nodes, index + 1);
}
}
到此這篇關(guān)于C#按路徑流式遍歷XML節(jié)點(diǎn)的實(shí)用方法的文章就介紹到這了,更多相關(guān)C#流式遍歷XML節(jié)點(diǎn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于C#?實(shí)現(xiàn)?OPC?DA?Server的問題小結(jié)
這篇文章主要介紹了基于C#?實(shí)現(xiàn)?OPC?DA?Server的相關(guān)知識,關(guān)于C#怎么編寫一個(gè)進(jìn)程外的DCOM組件,這里先不做介紹了,這里主要介紹下OPC?DA?Server?的第一個(gè)接口,感興趣的朋友跟隨小編一起看看吧2024-04-04
程序中兩個(gè)Double類型相加出現(xiàn)誤差的解決辦法
本篇文章介紹了,程序中兩個(gè)Double類型相加出現(xiàn)誤差的解決辦法。需要的朋友參考下2013-04-04
C#?守護(hù)進(jìn)程的介紹及實(shí)現(xiàn)詳解
本文主要介紹了C#?守護(hù)進(jìn)程的介紹及實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06

