【问题标题】:XmlReader ReadStartElement causes XmlExceptionXmlReader ReadStartElement 导致 XmlException
【发布时间】:2011-06-26 07:38:08
【问题描述】:

我正在 Silverlight 项目中使用 XmlReader 编写文件阅读器。但是,我遇到了一些错误(特别是在 XmlReader.ReadStartElement 方法周围),这让我相信我误解了如何在某个地方使用它。

基本上,这是我正在使用的 Xml 格式的示例:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<root>
    <EmptyElement />
    <NonEmptyElement Name="NonEmptyElement">
        <SubElement Name="SubElement" />
    </NonEmptyElement>
</root>

下面是一些代码示例,其使用方式与我使用它的方式相同:

public void ReadData(XmlReader reader)
{
    // Move to root element
    reader.ReadStartElement("root");

    // Move to the empty element
    reader.ReadStartElement("EmptyElement");

    // Read any children
    while(reader.ReadToNextSibling("SubEmptyElement"))
    {
        // ...
    }

    // Read the end of the empty element
    reader.ReadEndElement();

    // Move to the non empty element
    reader.ReadStartElement("NonEmptyElement");    // NOTE: This is where I get the error.

    // ...
}

所以,本质上,我只是试图读取每个元素和任何包含的子元素。我在突出显示的地方得到的错误如下:

错误说明

[Xml_InvalidNodeType] 参数:无,10,8 调试资源字符串不可用。通常,关键和论据提供了足够的信息来诊断问题。见http://go.microsoft.com/fwlink/?linkid=106663&Version=4.0.51204.0&File=System.Xml.dll&Key=Xml_InvalidNodeType

错误堆栈跟踪

在 System.Xml.XmlReader.ReadStartElement(字符串名称) 在----------------

对此的任何建议或指导将不胜感激。

编辑 由于此阅读器需要相当通用,因此可以假设 Xml 可能包含作为 EmptyElement 的子元素的元素。因此,读取任何 SubEmptyElements 的尝试应该是有效的。

【问题讨论】:

  • 读者读过孩子吗?
  • 在这个例子中,它没有读取 EmptyElement 的任何子元素,因为没有。

标签: c# .net silverlight xmlreader xmlexception


【解决方案1】:

&lt;SubElement/&gt; 不是&lt;EmptyElement&gt; 的兄弟,所以&lt;NonEmptyElement&gt; 将被完全跳过,您对ReadEndElement() 的调用将读取结束元素&lt;/root&gt;。当您随后尝试读取“NonEmptyElement”时,没有剩余元素,您将收到 XmlException: {"'None' is an invalid XmlNodeType. Line 8, position 1."}

还要注意,由于&lt;EmptyElement/&gt; 是空的,当您使用 ReadStartElement("EmptyElement") 时,您将读取整个元素,而无需使用 ReadEndElement()。

我还建议您将阅读器设置配置为 IgnoreWhitespace(如果您还没有这样做的话),以避免在您不期望它们时读取(无关紧要的)空白文本节点带来的任何并发症。

尝试将 NonEmptyElement 的 Read 向上移动:

public static void ReadData(XmlReader reader)
{
    reader.ReadStartElement("root");

    reader.ReadStartElement("EmptyElement");

    reader.ReadStartElement("NonEmptyElement");

    while (reader.ReadToNextSibling("SubEmptyElement"))
    {
        // ...
    }

    reader.ReadEndElement(/* NonEmptyElement */);

    reader.ReadEndElement(/* root */);
    // ...
}

如果您只想跳过&lt;EmptyElement&gt; 中的任何内容,无论其是否为空,请使用ReadToFollowing

public static void ReadData(XmlReader reader)
{
    reader.ReadStartElement("root");

    reader.ReadToFollowing("NonEmptyElement");

    Console.WriteLine(reader.GetAttribute("Name"));

    reader.ReadStartElement("NonEmptyElement");

    Console.WriteLine(reader.GetAttribute("Name"));
    while (reader.ReadToNextSibling("SubEmptyElement"))
    {
        // ...
    }

    reader.ReadEndElement(/* NonEmptyElement */);

    reader.ReadEndElement(/* root */);
    // ...
}

更新:这是一个更完整的示例,具有更清晰的数据模型。也许这更接近您的要求。

XMLFile1.xml:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<root>
  <Person Type="Homeless"/>
  <Person Type="Developer">
    <Home Type="Apartment" />
  </Person>
  <Person Type="Banker">
    <Home Type="Apartment"/>
    <Home Type="Detached"/>
    <Home Type="Mansion">
      <PoolHouse/>
    </Home>
  </Person>
</root>

程序.cs:

using System;
using System.Xml;

namespace ConsoleApplication6
{
    internal class Program
    {
        public static void ReadData(XmlReader reader)
        {
            reader.ReadStartElement("root");

            while (reader.IsStartElement("Person"))
            {
                ReadPerson(reader);
            }

            reader.ReadEndElement( /* root */);
        }

        public static void ReadPerson(XmlReader reader)
        {
            Console.WriteLine(reader.GetAttribute("Type"));
            bool isEmpty = reader.IsEmptyElement;
            reader.ReadStartElement("Person");
            while (reader.IsStartElement("Home"))
            {
                ReadHome(reader);
            }
            if (!isEmpty)
            {
                reader.ReadEndElement( /* Person */);
            }
        }

        public static void ReadHome(XmlReader reader)
        {
            Console.WriteLine("\t" + reader.GetAttribute("Type"));
            bool isEmpty = reader.IsEmptyElement;
            reader.ReadStartElement("Home");

            if (!isEmpty)
            {
                reader.Skip();
                reader.ReadEndElement( /* Home */);
            }
        }

        private static void Main(string[] args)
        {
            var settings = new XmlReaderSettings { IgnoreWhitespace = true };
            using (var xr = XmlReader.Create("XMLFile1.xml", settings))
            {
                ReadData(xr);
            }
            Console.ReadKey();
        }
    }
}

【讨论】:

  • 好的,有道理。但是,在 Xml 中,在 EmptyElement 中有子元素是有效的(我可能应该在问题中对此进行解释)。因此,我需要某种方法来确定在调用 ReadStartElement("EmptyElement") 之后是否调用 ReadToNextSibling 和 ReadEndElement。我曾尝试使用 IsEmptyElement,但这只会返回 false。有什么想法吗?
  • 你是说你想跳过 EmptyElement,不管它是否包含子元素?查看更新的答案。
  • 不不,我们的想法是实际阅读该元素。但是该元素可能包含子元素或不包含子元素。例如,假设您有一个人员数据库,并且 EmptyElement 实际上是 Children - 指的是一个人可能拥有或不拥有的孩子。如果该人没有孩子,则该元素将为空。但是,如果它们确实有子元素,则该元素中会有元素。所以,我的问题实际上是;你如何阅读那个元素,如果它有孩子,阅读那些,如果没有,跳到下一个元素(可能是父母,或其他东西)?
  • 我认为如果您发布一个更接近您的真实对象模型的示例会有所帮助。
  • 我猜到了更接近您真实架构的东西 - 请参阅更新的答案。
猜你喜欢
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多