XmlReader ReadStartElement вызывает XmlException - PullRequest
6 голосов
/ 13 февраля 2011

Я пишу программу для чтения файлов с использованием XmlReader в проекте Silverlight.Тем не менее, я получаю некоторые ошибки (в частности, о методе 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 должна быть действительной.

1 Ответ

6 голосов
/ 13 февраля 2011

<SubElement/> не является братом <EmptyElement>, поэтому <NonEmptyElement> будет полностью пропущен, и ваш вызов ReadEndElement() будет читать конечный элемент </root>.Когда вы попытаетесь впоследствии прочитать «NonEmptyElement», элементов не останется, и вы получите исключение XmlException: {«None» является недопустимым XmlNodeType. Строка 8, позиция 1. "}

Обратите внимание такжечто поскольку <EmptyElement/> пусто, при чтении ReadStartElement («EmptyElement») вы прочитаете весь элемент, и вам не нужно будет использовать ReadEndElement ().

Я также рекомендую вамнастройте параметры считывателя на IgnoreWhitespace (если вы этого еще не сделали), чтобы избежать каких-либо сложностей, возникающих при чтении (незначительных) пробельных текстовых узлов, когда вы их не ожидаете.

Попробуйте переместить Read of NonEmptyElementup:

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 */);
    // ...
}

Если вы просто хотите пропустить что-либо в <EmptyElement>, независимо от того, действительно ли оно пустое, используйте 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>

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