XmlReader不移动游标取值及读取XML到List<LogData>的问题
解决XmlReader读取值不移动游标及填充List的问题
我来帮你搞定这两个问题——先说说你遇到reader.Value为空和ReadString()移动游标导致跳过节点的原因,再给你完整的代码示例把XML数据读到List<LogData>集合里。
问题原因解析
reader.Value为空:XmlReader的Value属性只有在当前节点是文本节点、CDATA节点、属性节点这类有内容的节点时才会有值。如果你的游标停留在<Id>这种元素标签节点上,Value自然是空的。ReadString()移动游标:这个方法会从当前位置读取所有连续文本,然后直接把游标移到文本之后的节点,这就会打乱你后续的节点遍历逻辑,导致跳过原本要处理的内容。
不移动原游标读取值的方法
如果不想影响原XmlReader的游标位置,推荐用ReadSubtree()方法。它会创建一个独立的子阅读器,只负责处理当前元素及其子节点,操作这个子阅读器完全不会干扰原阅读器的位置。当你用完子阅读器并关闭后,原阅读器会自动回到当前元素的结束标签位置,不会打乱整体遍历流程。
完整读取XML到List的示例
首先我们先定义LogData类(假设你的日志数据包含Id、Message、Time三个字段,你可以根据实际XML结构调整):
public class LogData { public int Id { get; set; } public string Message { get; set; } public DateTime Time { get; set; } }
然后是读取XML的核心代码,这里我们用XmlReader的标准遍历逻辑,结合子阅读器安全读取值:
using System; using System.Collections.Generic; using System.Xml; using System.IO; namespace ReadXML { class Program { private static string XML = @"<?xml version=""1.0"" encoding=""UTF-8""?> <Logs> <Log> <Id>1</Id> <Message>Database connection failed</Message> <Time>2024-05-20 09:30:00</Time> </Log> <Log> <Id>2</Id> <Message>File upload succeeded</Message> <Time>2024-05-20 09:45:00</Time> </Log> </Logs>"; static void Main(string[] args) { List<LogData> logDatas = new List<LogData>(); // 用StringReader加载XML字符串 using (StringReader stringReader = new StringReader(XML)) using (XmlReader reader = XmlReader.Create(stringReader)) { while (reader.Read()) { // 只处理<Log>元素节点 if (reader.NodeType == XmlNodeType.Element && reader.Name == "Log") { // 创建子阅读器处理当前<Log>的子节点,不影响原阅读器位置 using (XmlReader logReader = reader.ReadSubtree()) { LogData log = new LogData(); while (logReader.Read()) { // 读取<Log>下的子元素值 if (logReader.NodeType == XmlNodeType.Element) { switch (logReader.Name) { case "Id": // 用ReadElementContentAsString读取值,自动移动到元素结束标签 log.Id = int.Parse(logReader.ReadElementContentAsString()); break; case "Message": log.Message = logReader.ReadElementContentAsString(); break; case "Time": log.Time = DateTime.Parse(logReader.ReadElementContentAsString()); break; } } } logDatas.Add(log); } } } } // 验证读取结果 foreach (var log in logDatas) { Console.WriteLine($"Id: {log.Id}, Message: {log.Message}, Time: {log.Time}"); } } } }
关键说明
- 用
ReadSubtree()处理单个<Log>节点,确保原阅读器的游标不会被打乱,避免跳过后续节点。 - 使用
ReadElementContentAsString()读取元素文本值,这个方法会自动从当前元素节点移动到结束标签,在子阅读器里操作完全不会影响原阅读器的遍历。 - 遍历节点时先判断
NodeType和Name,确保只处理我们需要的元素,避免无效操作。
另外,如果你的XML里有属性值(比如<Log id="1">),可以用reader.GetAttribute("id")来获取,这个方法不会移动游标,非常适合读取属性值。
内容的提问来源于stack exchange,提问作者paparazzo
相关产品推荐
相关产品推荐

