XmlReader ReadStartElement вызывает XmlException
Я пишу для чтения файлов с использованием 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 ответ
<SubElement/>
это не брат или сестра <EmptyElement>
, так <NonEmptyElement>
будет полностью пропущен, и ваш звонок ReadEndElement()
будет читать конечный элемент </root>
, Когда вы попытаетесь впоследствии прочитать "NonEmptyElement", не останется никаких элементов, и вы получите исключение XmlException: {"None" является недопустимым XmlNodeType. Строка 8, позиция 1."}
Обратите внимание, что с <EmptyElement/>
пусто, когда вы ReadStartElement("EmptyElement"), вы прочитаете весь элемент, и вам не нужно будет использовать ReadEndElement().
Я также рекомендую вам настроить параметры чтения на IgnoreWhitespace (если вы этого еще не сделали), чтобы избежать каких-либо сложностей, возникающих при чтении (незначительных) пробельных текстовых узлов, когда вы их не ожидаете.
Попробуйте переместить Read of NonEmptyElement вверх:
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();
}
}
}