解析XML时如何检查元素是否存在

37
我正在解析XML。我通常使用下面示例代码的方式进行解析,这很简单。问题在于,我不拥有我要解析的XML,并且无法更改它。有时候没有缩略图元素(没有标签),我会收到一个异常。
有没有一种方法可以保持这种简单性并检查元素是否存在?或者我必须先使用LINQ获取XElement列表,然后检查它并仅填充现有对象属性?
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    XDocument dataDoc = XDocument.Load(new StringReader(e.Result));

    var listitems = from noticia in dataDoc.Descendants("Noticia")
                    select new News()
                    {
                        id = noticia.Element("IdNoticia").Value,
                        published = noticia.Element("Data").Value,
                        title = noticia.Element("Titol").Value,
                        subtitle = noticia.Element("Subtitol").Value,
                        thumbnail = noticia.Element("Thumbnail").Value
                    };

    itemList.ItemsSource = listitems;
}
4个回答

51

[编辑]Jon Skeet的回答应该被采纳为最佳答案。它更易读且更易应用。[/编辑]

创建一个类似这样的扩展方法:

public static string TryGetElementValue(this XElement parentEl, string elementName, string defaultValue = null) 
{
    var foundEl = parentEl.Element(elementName);

    if (foundEl != null)
    {
        return foundEl.Value;
    }

    return defaultValue;
}

然后,将您的代码更改为以下形式:

select new News()
{
    id = noticia.TryGetElementValue("IdNoticia"),
    published = noticia.TryGetElementValue("Data"),
    title = noticia.TryGetElementValue("Titol"),
    subtitle = noticia.TryGetElementValue("Subtitol"),
    thumbnail = noticia.TryGetElementValue("Thumbnail", "http://server/images/empty.png")
};

使用这种方法可以使代码整洁,通过隔离元素存在检查。它还允许您定义默认值,这可能会有所帮助。


3
更好的方法是使用XElement中已经存在的显式转换和空值合并运算符来设置默认值... - Jon Skeet
嗨,在查找扩展方法和空合并运算符的含义之后,我已经实现了你给我的示例中的相同代码,但是在扩展方法内部,我有以下内容: return (parentEl.Element(elementName).Value ?? defaultValue);这正确吗?我一直得到NullReferenceException错误,现在出现在那行代码上。谢谢。 - enkara
你重现了相同的错误:如果 parentEl.Element(elementName) 为空,则无法检索 Value 属性。查看示例。仅在元素存在时才调用 .Value - Steve B
另外一个问题,创建扩展方法和创建普通方法有什么区别,在这种情况下将XElement作为另一个参数传递? - enkara
这只是语法问题。扩展方法允许您向现有对象添加方法,而实用程序方法需要将对象作为参数传递:myObject.MyExtensionMethod() 而不是 MyUtilityMethod(myobject) - Steve B
显示剩余5条评论

39

如果您强制类型转换为字符串,而不是使用Value属性,您将只得到一个空引用:

void wc_DownloadStringCompleted(object sender,
                                DownloadStringCompletedEventArgs e)
{
    XDocument dataDoc = XDocument.Load(new StringReader(e.Result));

    var listitems = from noticia in dataDoc.Descendants("Noticia")
                    select new News()
                    {
                        id = (string) noticia.Element("IdNoticia"),
                        published = (string) noticia.Element("Data"),
                        title = (string) noticia.Element("Titol"),
                        subtitle = (string) noticia.Element("Subtitol"),
                        thumbnail = (string) noticia.Element("Thumbnail")
                    };

    itemList.ItemsSource = listitems;
}

这里使用了从XElementstring的显式转换,它处理null输入并返回null输出。同样适用于所有XAttributeXElement到可为空类型的显式转换,包括可空值类型,比如int?,只需注意嵌套元素的情况。例如:

string text = (string) foo.Element("outer").Element("inner");

如果inner不存在,则会出现空引用;但是如果outer不存在,则仍会抛出异常。

如果想要一个“默认”值,可以使用空合并运算符??

string text = (string) foo.Element("Text") ?? "Default value";

0

0
您可以使用以下代码:

string content = item.Element("Content") == null ? "" : item.Element("Content").Value;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接