为什么XmlReader会跳过元素?

时间:2016-04-28 08:54:06

标签: c# .net xmlreader

请注意,此问题仅针对XmlReader,而不是{@ 1}}或XDocument

我有一个 XML 片段:

XmlReader

我还有一个扩展方法:

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>";
}

然后我尝试通过执行以下操作来获取两个public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName) { reader.MoveToElement(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name.Equals(elementName, StringComparison.InvariantCulture)) { yield return XNode.ReadFrom(reader) as XElement; } } } 元素:

book

但是我只得到第一个元素,调试显示,只要我得到第一个元素,读者就会跳转到第二个var xmlReaderSettings = new XmlReaderSettings { CheckCharacters = false, ConformanceLevel = ConformanceLevel.Fragment, IgnoreComments = true, IgnoreWhitespace = true, IgnoreProcessingInstructions = true }; using (var stringReader = new StringReader(this.GetXmlFragment())) using (var xmlReader = XmlReader.Create(stringReader, xmlReaderSettings)) { xmlReader.GetElement("book").Count().ShouldBe(2); } 元素的title

该解决方案的灵感来自HERE

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:3)

问题在于,如果没有插入的空格,对XNode.ReadFrom()的调用将使XML阅读器位于下一个元素的正确位置。 while条件然后立即消耗此元素,然后才能检查它。修复之后不要立即调用XmlReader.Read(),而是继续检查节点(因为读取已经隐式完成):

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

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

答案 1 :(得分:1)

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();
}

答案 2 :(得分:0)

代码正在跳过所有其他书签,因为书签会立即相互跟随。 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;
        }

答案 3 :(得分:0)

正如其他人所说,XNode.ReadFrom正在推动读者进入下一本书的开放标签(如果它们之间没有空格)那么reader.Read会前进到该标签的内部文本。

有关详细信息,请参阅此处:

https://stackoverflow.com/a/26788230/3850405

修复扩展方法:

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();
        }
    }
}