C# 为什么XmlReader会跳过元素?

C# 为什么XmlReader会跳过元素?,c#,.net,xmlreader,C#,.net,Xmlreader,请注意,此问题只针对XmlReader,而不是是否使用XDocument或XmlReader 我有一个XML片段,如下所示: private string GetXmlFragment() { return @"<bookstore> <book genre='novel' ISBN='10-861003-324'> <title>The Handmaid's Tale</title>

请注意,此问题只针对
XmlReader
,而不是是否使用
XDocument
XmlReader

我有一个XML片段,如下所示:

private string GetXmlFragment()
{
    return @"<bookstore>
          <book genre='novel' ISBN='10-861003-324'>
            <title>The Handmaid's Tale</title>
            <price>19.95</price>
          </book>
          <book genre='novel' ISBN='1-861001-57-5'>
            <title>Pride And Prejudice</title>
            <price>24.95</price>
          </book>
        </bookstore>";
}
然而,我只得到第一个元素,调试表明,一旦我得到第一个元素,读者就会跳转到第二个
book
元素的
title

该解决方案的灵感来自


非常感谢您的帮助。

问题是,如果没有中间空白,调用
XNode.ReadFrom()
将使XML读取器位于下一个元素的正位置。
while
条件会在我们检查之前立即消耗该元素。修复方法是不立即调用
XmlReader.Read()
,而是继续检查节点(因为读取是隐式完成的):

(如果不清楚,循环中的
if
已更改为
,而

公共静态IEnumerable GetElement(此XmlReader阅读器,string elementName)
{
而(!reader.EOF)
if(reader.NodeType==XmlNodeType.Element&&reader.Name==book)
返回XNode.ReadFrom(reader)作为XElement;
其他的
reader.Read();
}

代码会跳过其他每一个图书标签,因为图书标签会紧跟其后。read方法将阅读器留在下一个book标记处,然后read方法在读取第二个book标记之前移动,跳过元素。试试下面我开发的代码,它总是有效的

        public static IEnumerable<XElement> GetElement(XmlReader reader, string elementName)
        {
            List<XElement> books = new List<XElement>();


            while (!reader.EOF)
            {
                if(reader.Name != "book")
                {
                    reader.ReadToFollowing("book");
                }
                if(!reader.EOF)
                {
                    books.Add((XElement)XElement.ReadFrom(reader));
                }
            }
            return books;
        }
公共静态IEnumerable GetElement(XmlReader阅读器,string elementName) { 列表书籍=新列表(); 而(!reader.EOF) { if(reader.Name!=“book”) { 读者。阅读以下内容(“书”); } if(!reader.EOF) { books.Add((XElement)XElement.ReadFrom(reader)); } } 还书; }
正如其他人所说,XNode.ReadFrom将您的读者推进到下一个图书打开标记(如果它们之间没有空格)然后reader.Read将推进到该标记的内部文本

有关更多信息,请参见此处:

修复您的扩展方法:

public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName)
{
    reader.MoveToElement();

    reader.Read();
    while (!reader.EOF)
    {
        if (reader.NodeType == XmlNodeType.Element 
            && reader.Name.Equals(elementName, StringComparison.InvariantCulture))
        {
            yield return XNode.ReadFrom(reader) as XElement;
        }
        else
        {
            reader.Read();
        }
    }
}
公共静态IEnumerable GetElement(此XmlReader读取器,string elementName)
{
reader.MoveToElement();
reader.Read();
而(!reader.EOF)
{
if(reader.NodeType==XmlNodeType.Element
&&reader.Name.Equals(elementName、StringComparison.InvariantCulture))
{
返回XNode.ReadFrom(reader)作为XElement;
}
其他的
{
reader.Read();
}
}
}

无法复制。您的方法在我的机器上生成一个包含两个元素的序列。您确定
this.GetXmlFragment()
生成了您提供的XML吗?奇怪的是,我已经更新了这个问题,将方法包括在内,请参见。您的调试是否有干扰?Can confirm-方法按预期工作我忘了包含
XmlReaderSettings
我已更新了问题,设置
IgnoreWhitespace=false
行为正常,但将其设置为
true
会导致跳转。
while (reader.Read()) {
    while (reader.NodeType == XmlNodeType.Element 
           && reader.Name.Equals(elementName, StringComparison.InvariantCulture)) {
        yield return XNode.ReadFrom(reader) as XElement;
    }
}
public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName)
{
    while (!reader.EOF)
        if (reader.NodeType == XmlNodeType.Element && reader.Name == "book")
            yield return XNode.ReadFrom(reader) as XElement;
        else
            reader.Read();
}
        public static IEnumerable<XElement> GetElement(XmlReader reader, string elementName)
        {
            List<XElement> books = new List<XElement>();


            while (!reader.EOF)
            {
                if(reader.Name != "book")
                {
                    reader.ReadToFollowing("book");
                }
                if(!reader.EOF)
                {
                    books.Add((XElement)XElement.ReadFrom(reader));
                }
            }
            return books;
        }
public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName)
{
    reader.MoveToElement();

    reader.Read();
    while (!reader.EOF)
    {
        if (reader.NodeType == XmlNodeType.Element 
            && reader.Name.Equals(elementName, StringComparison.InvariantCulture))
        {
            yield return XNode.ReadFrom(reader) as XElement;
        }
        else
        {
            reader.Read();
        }
    }
}