我有这个代码用于读取XML文件:
using (XmlReader reader = XmlReader.Create(path + "\\AddressBook\\settings.xml"))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
if (reader.Name == "Person")
{
Person p = new Person();
reader.Read();
reader.Read();
// Get name
p.name = reader.Value;
reader.Read(); // skip end tag of previous element
reader.Read(); // read start tag of email
reader.Read(); // read email value
// Get email
p.email = reader.Value;
reader.Read();
reader.Read();
reader.Read();
// Get first name
p.address = reader.Value;
reader.Read();
reader.Read();
reader.Read();
// Get notes
p.notes = reader.Value;
reader.Read();
reader.Read();
reader.Read();
// Get dob
p.dob = DateTime.Parse(reader.Value);
lPeople.Add(p);
}
}
}
}
它正在运行,但在这个XML元素上失败了:
<Person>
<Name />
<Email />
<StreetAddress />
<Notes>note</Notes>
<DateOfBirth>5/20/2015 8:04:15 PM</DateOfBirth>
</Person>
它失败了,因为您可以看到我添加空元素作为名称,电子邮件和地址没有添加的开始和结束标记(由XMLWriter
),而只是<Name/>
,因此我的阅读逻辑失败通过阅读错误的元素。通常有哪些解决方法?
注意:here使用扩展方法的答案由于某些原因对我不起作用,仍然没有为空元素编写开始和结束标记
更新:以下Jon Hanna的答案对我不起作用。如果我读了一些元素,那么会发生什么?&#34; Email&#34;一旦ReadElementContentAsString
被调用,它似乎会跳到其他元素上,例如&#34; Notes&#34;。顺便说一句this是与它失败的XML的链接J.汉娜的方法
答案 0 :(得分:0)
可以进行简单的空检查。
if(reader.value == null)
p.name = "";
else
p.name = reader.value;
虽然说这不是读取XML的理想方式,但您可能希望使用允许类似SQL查询的操作来检索数据的LINQ to XML,或者使用早于LINQ的System.Xml.XmlDocument
XML,但仍在使用中。 Here is a tutorial for that。
This SO Question also mentions how to use XMLDocuments to read an XML,您可以使用上述方法将数据从XML检索到人员类,如果没有可用值,则会给出null
值。这样您就不必通过手动执行reader.Read()
来对您的方法进行硬编码,如果XML与更少/更多元素略有不同,您的方法也会失败。
This tutorial also goes over the basics示例与您尝试实现的示例非常相似。
在OP的评论后编辑
如果这种天真的方法是您想要继续进行的方式,那么很可能符合某项要求,例如在任务中,然后继续做您正在做的事情,但添加一个开关案例来检查您所在的节点。处理。
if (reader.Value == null)
continue;
switch(reader.Name)
{
case "Email":
person.Email = reader.Value;
break;
case "Address":
person.Address = reader.Value;
break;
}
答案 1 :(得分:0)
这不是&#34;解决方法&#34;。您已经编写了一个只接受给定格式的解析器,然后以另一种格式传入XML。
首先,如果你可以获得空元素,那么检查reader.IsEmptyElement
是有意义的。
你仍然期望给定元素之间有一定数量的文本节点,但这并不是很有弹性。
我更喜欢以下内容:
using (var reader = XmlReader.Create(path + @"\AddressBook\settings.xml"))
while (reader.Read())
if (reader.IsStartElement() && reader.Name == "Person")
people.Add(ReadPerson(reader.ReadSubtree()));
然后ReadPerson()
让我担心那个元素:
private static Person ReadPerson(XmlReader rdr)
{
var person = new Person();
using(rdr)
while(rdr.Read())
if(rdr.IsStartElement())
switch(rdr.Name)
{
case "Name":
person.Name = rdr.ReadElementContentAsString();
break;
case "Email":
person.Email = rdr.ReadElementContentAsString();
break;
case "StreetAddress":
person.Address = rdr.ReadElementContentAsString();
break;
case "Notes":
person.Notes = rdr.ReadElementContentAsString();
break;
case "DateOfBirth":
person.DateOfBirth = DateTime.Parse(rdr.ReadElementContentAsString(), CultureInfo.GetCultureInfo("en-US"));
break;
}
return person;
}
(虽然如果我知道谁对这个XML负责,我会请求他们将日期时间从在美国筹集的人的日期时间替换为用于XML解析软件的日期时间:2015-05-20T20:04:15
。
面对元素的重新排序,元素之间的空白量以及空元素,这是有弹性的。
我当然也考虑将people.Add(ReadPerson(reader.ReadSubtree()))
替换为yield ReadPerson(reader.ReadSubtree())
。然后调用代码可以创建它自己的列表,如果它需要列表,但是否则可以使用Person
对象。