为啥 XmlReader 跳过标签?
Posted
技术标签:
【中文标题】为啥 XmlReader 跳过标签?【英文标题】:Why is XmlReader skipping tags?为什么 XmlReader 跳过标签? 【发布时间】:2019-01-19 10:44:18 【问题描述】:XmlReader 正在跳过标签,我不知道为什么。如果你执行下面的代码,你会看到 ID 123 和 789 被打印出来,这意味着 456 被跳过了。如果您运行使用 1234 的替代内存流,您将看到仅打印 123 和 456 意味着 1234 和 789 被跳过。
这是主要部分。完整代码如下。我创建了一个带有流的 XML 阅读器,我有一个 while 循环,我检查我想要的深度(因为节点不在深度 0 处)。 XElement.ReadFrom(root) as XElement
根据我的理解读取 XML 直到标签关闭,这就是我想要的。然后我简单地打印出 id 值。很简单,不到10行代码
var root = XmlReader.Create(fs);
root.MoveToElement();
while (root.Read())
if (root.NodeType == XmlNodeType.EndElement || root.Depth != 1)
continue;
var el = XElement.ReadFrom(root) as XElement;
Console.WriteLine(el.Attribute("id").Value);
如果我在</node><node>
之间添加换行符,它不会跳过标签,但感觉就像是创可贴,我不确定我的输入是否会在</node>
之后有换行符。
using System.Xml.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace nearMe
class Program
static void Main(string[] args)
using (var fs = new MemoryStream(UTF8Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?><test><node id=""123"">
<tag k=""amenity"" v=""fuel"" />
</node><node id=""456"">
<tag k=""name"" v=""B"" />
</node><node id=""789"">
<tag k=""amenity"" v=""test"" />
</node></test>")))
var root = XmlReader.Create(fs);
root.MoveToElement();
while (root.Read())
if (root.NodeType == XmlNodeType.EndElement || root.Depth != 1)
continue;
var el = XElement.ReadFrom(root) as XElement;
if (el == null)
continue;
if (el.Name != "node")
continue;
Console.WriteLine(el.Attribute("id").Value);
using (var fs = new MemoryStream(UTF8Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?>
<test>
<node id=""123"">
<tag k=""amenity"" v=""fuel"" />
</node>
<node id=""1234"">
<tag k=""amenity"" v=""fuel"" />
</node>
<node id=""456"">
<tag k=""name"" v=""B"" />
</node>
<node id=""789"">
<tag k=""amenity"" v=""test"" />
</node>
</test>"
)))
【问题讨论】:
您可能已经注意到,每隔一个元素就会被跳过。除此之外,如果您知道节点名称,我建议您按名称读取节点。恕我直言,阅读更容易。 您没有获得所有元素的原因是由于获得了第一个节点,然后您位于第二个节点,然后跳过第二个节点移动到下一个节点。我的解决方案检查你是否在一个节点上,所以你不要移动。 【参考方案1】:在类似问题的评论中指出了您的错误:
调用 [
XElement.ReadFrom
] 读取元素并转到下一个元素,然后以下 [root.Read()
] 再次读取下一个元素。如果它们碰巧具有相同的名称并且是连续的,那么您基本上会错过一个元素。 (pbz)
解决此问题的最简单方法是删除 ReadFrom
并继续从阅读器获取值:
while (root.Read())
if (root.NodeType != XmlNodeType.Element ||
root.Depth != 1 ||
root.Name != "node")
continue;
Console.WriteLine(root.GetAttribute("id"));
【讨论】:
【参考方案2】:using (var fs = new FileStream("test.xml", FileMode.Open, FileAccess.Read))
var test = XElement.Load(fs);
var nodes = test.XPathSelectElements("node[@id]");
foreach (var node in nodes)
Console.WriteLine(node.Attribute("id").Value);
【讨论】:
【参考方案3】:使用下面的代码。它不会跳过并使用 xml 阅读器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
class Program
static void Main(string[] args)
using (var fs = new MemoryStream(UTF8Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?><test><node id=""123"">
<tag k=""amenity"" v=""fuel"" />
</node><node id=""456"">
<tag k=""name"" v=""B"" />
</node><node id=""789"">
<tag k=""amenity"" v=""test"" />
</node></test>")))
XmlReader reader = XmlReader.Create(fs);
while (!reader.EOF)
if(reader.Name != "node")
reader.ReadToFollowing("node");
if(!reader.EOF)
XElement node = (XElement)XElement.ReadFrom(reader);
int id = (int)node.Attribute("id");
Console.WriteLine(id.ToString());
Console.ReadLine();
【讨论】:
以上是关于为啥 XmlReader 跳过标签?的主要内容,如果未能解决你的问题,请参考以下文章