遇到空元素

时间:2015-05-20 16:08:54

标签: c# xml

我有这个代码用于读取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.汉娜的方法

2 个答案:

答案 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与更少/更多元素略有不同,您的方法也会失败。

LINQ to 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对象。