【问题标题】:LINQ to XML: handling nodes that do not exist?LINQ to XML:处理不存在的节点?
【发布时间】:2009-12-04 20:45:06
【问题描述】:

这可能是一个简单的修复(嗯,它可能是),但由于某种原因我无法弄清楚。

所以,我有一些看起来像这样的 xml:

XElement xml = XElement.Parse (
@"<Alphabet>
     <a name="A" />
     <b name="B" />
     <d name="D" />
     <e name="E" />
</Alphabet>");

所以稍后在我的代码中,我引用了一个可能存在也可能不存在的节点,如下所示:

var name = (from b in xml.Descendants("c")
            select b.Attribute("name")).FirstOrDefault().Value;

但是当它不存在时,它不会返回 null 或 "" 而是抛出 NullReferenceException: Object reference not set to an instance of an object。

检查和查看我的 linq 查询中是否确实存在节点的最佳方法是什么?还是我需要以其他方式检查它是否存在?

【问题讨论】:

  • 看来是我对 FirstOrDefault() 的使用搞砸了。不过感谢您的回答 - 都非常有帮助!
  • 你能解决这个问题吗?
  • @trx - 我在发布此问题时遇到的问题是在我的FirstOrDefault() 查询中调用Value。由于查询返回 null,因此对其调用 Value 会导致错误。所以要测试节点是否存在,我应该写:var name = (from b in xml.Descendants("c") select b.Attribute("name")).FirstOrDefault(); 并检查name 看它是否为空。

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


【解决方案1】:

好吧,您正在选择属性 - 所以只需使用:

var nameAttribute = xml.Descendants("c").Select(b => b.Attribute("name"))
                                        .FirstOrDefault();
if (nameAttribute != null)
{
    string name = nameAttribute.Value;
}
else
{
    // Whatever...
}

(我已将其从查询表达式更改为点表示法,因为查询很简单 - 查询表达式语法实际上并没有给您带来任何好处。)

这个解决方案的一个问题:它没有区分存在“c”元素但它没有“name”属性,以及首先没有“c”元素。您需要能够分辨出其中的区别吗?

【讨论】:

  • 感谢您的回答 - 不,我不需要能够分辨出其中的区别,所以这会很好用。我对您说“查询表达式语法实际上并没有给您带来任何好处”很感兴趣-我一直认为选择一种语法而不是另一种语法是基于偏好-实际上是否有性能原因在查询表达式上加点符号?或者,也许这是一个完全不同的主题。谷歌我来了!
  • @Skeet - Ayende 也为 Linq 说了些什么。想详细说明为什么它是有益的?
  • 根本没有性能原因——只是在这种情况下“从 x 到 y”只是额外的绒毛。见msmvps.com/blogs/jon_skeet/archive/2009/01/07/…
  • @Jon:在尝试解决我的问题时,我找到了您的答案,但在理解问题所在时遇到了问题。我有一个简单的任务,string variable_name = x.Attributes("variable").FirstOrDefault().Value;。这不起作用,因为如果 variable 元素不存在(它在我的架构中是可选的),FirstOrDefault() 将为空,并且您不能取消引用 Value。结果,我得到了一个例外。我可以在使用 Value 之前检查 null,但想跳过您在解决方案中显示的额外步骤。没有办法做到这一点吗?
  • @Dave:不使用Value 属性,而是将整个表达式转换为string - 如果使用@987654330 调用XAttributestring 的显式转换,则返回null @参数。
【解决方案2】:

我为此创建了扩展方法。

public static string GetAttributeValue(this XElement element, string attributeName)
{
    XAttribute attribute = element.Attribute(attributeName);
    return attribute != null ? attribute.Value : string.Empty;
}

public static string GetElementValue(this XElement element)
{
    return element != null ? element.Value : string.Empty;
}

public static string GetElementValue(this XElement element, string elementName)
{
    XElement child = element.Element(elementName);
    return child != null ? child.Value : string.Empty;
}

【讨论】:

  • 嘿,很好。我会用那些。我怎么没想到呢。
【解决方案3】:

FirstOrDefault 返回nullXAttribute,您可以将其转换为string 以获取值:

var name = (string)((from b in xml.Descendants("c")
                     select b.Attribute("name")).FirstOrDefault());

var name = (string)xml.Descendants("c")
                      .Select(b => b.Attribute("name"))
                      .FirstOrDefault();

【讨论】:

    【解决方案4】:

    你可以这样做:

    var name = (from b in xml.Descendants("c")
                select b.Attribute("name").Value).FirstOrDefault();
    

    或者如果你真的需要这个元素:

    var name = (from b in xml.Descendants("c")
                select b.Attribute("name")).FirstOrDefault();
    
    if (name != null)
    {
        // your logic ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多