【问题标题】:Handling null XElements whilst parsing an XDocument在解析 XDocument 时处理 null XElements
【发布时间】:2014-04-10 10:36:44
【问题描述】:

有没有更好的方法来做这样的事情:

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

因此会发生对象引用错误(假设未找到元素/属性)。尝试访问元素值时相同

【问题讨论】:

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

标签: c# xml error-handling linq-to-xml


【解决方案1】:

我只会使用扩展方法。是一样的,但更漂亮:

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;

【讨论】:

  • 我还会为元素添加对 null 的检查。如果目标在任何情况下都不会失败,我会将 XName 类型替换为字符串并检查 IsNullOrWhiteSpace (但它可能导致意外错误,这可能很难处理)
【解决方案2】:

在 C# 6.0 中,您可以使用一元空条件运算符 ?. 在您的示例中应用它后,它将如下所示:

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

如果 fooelement 或 fooattribute 不存在,整个表达式将导致 null。您可以阅读更多 here 部分标题为空条件运算符。

【讨论】:

    【解决方案3】:

    不确定这是一种更好的方法,但我在 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")
    

    不确定它是否比使用那些家伙在之前的帖子中已经建议的简单扩展方法更漂亮,但它更通用并且是 IMO 的一个不错的方法

    CodeProject - Chained null checks and the Maybe monad

    【讨论】:

    • 我认为这是最好的方法,因为它允许我传入一个默认值而不是返回一个新的XElement。它也很有用,因为它可以用于任何类型,而不仅仅是XElement
    【解决方案4】:

    这样试试;

    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")
                    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-28
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-01
      相关资源
      最近更新 更多