为什么XmlReader跳过元素?

请注意,此问题特定于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>";
}

我也有一个扩展方法为:

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

然后,我尝试通过执行以下操作获得两个书本元素:

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

但是,我仅获得第一个元素,调试显示,一旦获得第一个元素,读者就会跳到第二本书元素的标题.

该解决方案的灵感来自HERE

任何帮助深表感谢.

解决方法:

问题是,如果没有中间的空格,则对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更改为一会儿.)

上一篇:HTML实体的PHP XMLReader问题


下一篇:从Xsd.exe使用XmlReader和类反序列化Xml