使用Linq / C#检索嵌套XML元素的空对象引用

时间:2011-12-08 15:50:12

标签: c# linq

这是我正在解析的XML:

<FEED>
<FEED_HEADER>
    <FEED_NAME>foo</FEED_NAME>
    <FEED_CODE>foobar123</FEED_CODE>
</FEED_HEADER>
<FEED_CONTENT>
    <DOC>
        <PUB_DATE>2011-12-01</PUB_DATE>
        <TITLE>Monkey Bombs</TITLE>
    </DOC>
    <DOC>
        <PUB_DATE>2011-12-10</PUB_DATE>
        <TITLE>A Silly Hat</TITLE>
    </DOC>
    <DOC>
        <PUB_DATE>2011-12-25</PUB_DATE>
        <TITLE>Wind Blows Up My Skirt</TITLE>
    </DOC>
</FEED_CONTENT>
</FEED>

我正在使用我编写的linq代码解析它,以基于DOC元素及其后续元素构建对象列表:

public List<Review> GetReviews(string filePath, FileInfo file, DirectoryInfo directory, XElement xmlDoc)
    {
        IEnumerable<BookReview> reviews = null;
        try
        {
            reviews = from item in xmlDoc.Descendants("DOC")
                      select new BookReview()
                      {
                          PubDate = item.Element("PUB_DATE").Value,
                          Title = item.Element("TITLE").Value,
                      };
        }
        catch (Exception ex)
        {
            logger.Info(string.Format("Error while parsing file {0}\n", file.Name) + " " + ex.Message.ToString());
        }

        return reviews.Cast<Review>().ToList();
    }

过去,这个代码适用于DOC元素位于根元素之下的情况,现在DOC元素进一步嵌套到FEED_CONTENT元素中,我得到一个空引用异常。我认为LINQ可以直接访问我想要的内容而不知道它在层次结构中的位置。 那么我现在需要编写什么才能访问DOC元素?

3 个答案:

答案 0 :(得分:3)

根据您当前的XML示例,您当前的查询应该可以正常工作。我怀疑您的真实XML文档缺少PUB_DATETITLE元素,这会导致NullReferenceException被抛出。

在这种情况下,您可以将元素转换为字符串,而不是尝试访问Value属性。如果该元素不存在,它将返回一个null结果,您需要通过稍后在过程中编写其他逻辑来正确处理。

PubDate = (string)item.Element("PUB_DATE"),
Title = (string)item.Element("TITLE")

答案 1 :(得分:2)

我运行了你的代码 - 我遇到的一个问题是你的元素需要关闭。在我以这种方式修改XML之后,我能够很好地处理DOC元素。这是我运行的代码:

        public class Review { }
        public class BookReview : Review
        {
            public string PubDate;
            public string Title;

        }
        public static void Main()
        {
            string xml = @"
<FEED>
<FEED_HEADER>
    <FEED_NAME>foo</FEED_NAME>
    <FEED_CODE>foobar123</FEED_CODE>
</FEED_HEADER>
<FEED_CONTENT>
    <DOC>
        <PUB_DATE>2011-12-01</PUB_DATE>
        <TITLE>Monkey Bombs</TITLE>
    </DOC>
    <DOC>
        <PUB_DATE>2011-12-10</PUB_DATE>
        <TITLE>A Silly Hat</TITLE>
    </DOC>
    <DOC>
        <PUB_DATE>2011-12-25</PUB_DATE>
        <TITLE>Wind Blows Up My Skirt</TITLE>
    </DOC>
</FEED_CONTENT>
</FEED>";   // NOTE: I closed  the <FEED> element!
            var xmlDoc = XDocument.Parse(xml);
            IEnumerable<BookReview> reviews = null;
            try
            {
                reviews = from item in xmlDoc.Descendants("DOC")
                          select new BookReview()
                          {
                              PubDate = item.Element("PUB_DATE").Value,
                              Title = item.Element("TITLE").Value,
                          };
            }
            catch (Exception ex)
            {
                //...
            }

            foreach (var review in reviews)
            {
                Console.WriteLine("{0}, {1}", review.PubDate, review.Title);
            } 
            var reviews2 = reviews.Cast<Review>().ToList();

            Console.ReadLine();
        }

输出:

2011-12-01, Monkey Bombs
2011-12-10, A Silly Hat
2011-12-25, Wind Blows Up My Skirt

答案 2 :(得分:0)

您可以从查询中进入FEED_CONTENT。这就像

reviews = from item in xmlDoc.Element("FEED_CONTENT").Descendants("DOC")
    select new BookReview()
    {
        PubDate = item.Element("PUB_DATE").Value,
        Title = item.Element("TITLE").Value
    }
};