我正在使用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
错误堆栈跟踪
at System.Xml.XmlReader.ReadStartElement(String name) 在----------------
对此有任何建议或指示将不胜感激。
修改 由于此读取器需要相当通用,因此可以假设Xml可能包含EmptyElement的子元素。因此,读取任何SubEmptyElements的尝试应该是有效的。
答案 0 :(得分:6)
<SubElement/>
不是<EmptyElement>
的兄弟,因此<NonEmptyElement>
将完全被跳过,而您对ReadEndElement()
的调用将会读取结束元素</root>
}。当您尝试随后读取“NonEmptyElement”时,没有剩余元素,并且您将获得XmlException:{“'None'是无效的XmlNodeType。第8行,位置1。”}
另请注意,由于<EmptyElement/>
为空,当您使用ReadStartElement(“EmptyElement”)时,您将读取整个元素,而不需要使用ReadEndElement()。
我还建议您将阅读器设置配置为IgnoreWhitespace(如果您还没有这样做),以避免在您不期望它们时读取(无关紧要的)空白文本节点所引起的任何复杂情况。
尝试向上移动读取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();
}
}
}