解析XDocument时处理空的XElements

4
有没有更好的方法来完成像这样的事情:
private XElement GetSafeElem(XElement elem, string key)
{
    XElement safeElem = elem.Element(key);
    return safeElem ?? new XElement(key);
}

private string GetAttributeValue(XAttribute attrib)
{
    return attrib == null ? "N/A" : attrib.Value;
}

var elem = GetSafeElem(elem, "hdhdhddh");
string foo = GetAttributeValue(e.Attribute("fkfkf"));

//attribute now has a fallback value

在解析XML文档时遇到元素/属性值找不到的情况?有些情况下,执行以下操作时可能无法找到元素:

string foo (string)elem.Element("fooelement").Attribute("fooattribute").Value

如果找不到元素/属性,就会出现对象引用错误。当尝试访问元素值时也是如此。


2
https://dev59.com/1XDYa4cB1Zd3GeqPB5Mp, https://dev59.com/8G855IYBdhLWcg3wcz5h, https://dev59.com/H3RA5IYBdhLWcg3w4iF_ - GSerg
我知道这并没有回答你的问题,但是你可能会对一种名为XPATH的技术感兴趣,它可以非常优雅地处理这种问题(尽管它也有自己的问题)。 - Simon Mourier
或者您可以在解决方案中创建一个仅用于托管解析XML代码的VB.NET项目。在VB中,您可以编写foo = elem.<fooelement1>.<fooelement2>.<fooelement3>.@fooattribute,如果链中的任何节点未找到,则它将返回一个空字符串。 - GSerg
4个回答

5
我建议您使用扩展方法,它和原来的方法一样,但更加简洁美观:
public static XElement SafeElement(this XElement element, XName name)
{
    return element.Element(name) ?? new XElement(name);
}

public static XAttribute SafeAttribute(this XElement element, XName name)
{
    return element.Attribute(name) ?? new XAttribute(name, string.Empty);
}

然后您可以执行以下操作:
string foo = element.SafeElement("fooelement").SafeAttribute("fooattribute").Value;

1
我还会添加对元素为空的检查。如果目标是在任何情况下都不失败,我会将XName类型替换为字符串并检查IsNullOrWhiteSpace(但这可能会导致意外错误,难以处理)。 - Igor Tkachenko

3
在C#6.0中,你可以使用单子空值运算符?.将其应用到你的示例中后,它看起来会像这样:
string foo = elem.Element("fooelement")?.Attribute("fooattribute")?.Value;

如果foo元素或foo属性不存在,则整个表达式将导致null。您可以在标题为Null-conditional operators的部分此处了解更多信息。

2

我不确定这是否是更好的方法,但我在CodeProject的帖子中看到了它,并认为它可能在这里是有用的解决方案。

这是一种使用“With”扩展方法的单子解决方案:

public static TResult With<TInput, TResult>(this TInput o, 
       Func<TInput, TResult> evaluator)
       where TResult : class where TInput : class
{
  if (o == null) return null;
  return evaluator(o);
}

以及一个返回扩展方法:

public static TResult Return<TInput,TResult>(this TInput o, 
       Func<TInput, TResult> evaluator, TResult failureValue) where TInput: class
{
  if (o == null) return failureValue;
  return evaluator(o);
}

将它们结合起来,你的查询可能是这样的:

var myElement = element.With(x => x.Element("FooElement")).Return(x => x.Attribute("FooAttribute").Value, "MyDefaultValue")

我不确定这种方法比之前其他帖子中提到的简单扩展方法更好看,但它更加通用,我认为这是一个不错的方法。

CodeProject - 链式空值检查和 Maybe Monad


1
我认为这是最好的方法,因为它允许我传递一个默认值,而不是返回一个新的 XElement。它还很有用,因为它可以用于任何类型,而不仅仅是 XElement - dtsg

0

尝试这种方式;

public static string TryGetElementValue(this XElement parentEl, string elementName, string defaultValue = null) 
{
    var foundEl = parentEl.Element(elementName);
    if(foundEl != null)
    {
     return foundEl.Value;
    }
else
{
     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")
                };

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