C# 带有LINQ Select和可选元素的XElement

C# 带有LINQ Select和可选元素的XElement,c#,xml,linq,C#,Xml,Linq,我试图显示从外部服务获取的XML中的一些日期。我正在使用XElement并尝试使用LINQ select获取数据 var xElem = XElement.Load(HttpUtility.UrlPathEncode(url)); var books = (from pubs in xElem.Elements("result") select new { Id = (string)pubs.Element("

我试图显示从外部服务获取的XML中的一些日期。我正在使用XElement并尝试使用LINQ select获取数据

var xElem = XElement.Load(HttpUtility.UrlPathEncode(url));
var books = (from pubs in xElem.Elements("result")
             select new
             {
                 Id = (string)pubs.Element("data").Element("id"),
                 Title = (string)pubs.Element("data").Element("title"),
                 Year = (string)pubs.Element("data").Element("year"),
                 Resources = (string)pubs.Element("data")
                                         .Element("resource")
                                         .Element("url")
                                         .ElementValueNull(),
                 Authors= pubs.Element("data").Elements("person")
             }).ToList();
foreach (var book in books)
{
    // Put the string together with string builder....
    foreach (var person in book.Authors)
    {
        //Get the authors
    }
}
当然,我已经为ElementValueNull创建了类

//This method is to handle if element is missing
public static string ElementValueNull(this XElement element)
{
    if (element != null)
        return element.Value;

    return "";
}

//This method is to handle if attribute is missing
public static string AttributeValueNull(this XElement element, string attributeName)
{
    if (element == null)
        return "";
    else
    {
        XAttribute attr = element.Attribute(attributeName);
        return attr == null ? "" : attr.Value;
    }
}
问题是带有元素的资源标记并不总是存在。如果没有,它将跳过整个记录。是否有任何简单的方法可以使资源只从我的类返回空字符串,但仍然使用LINQ select添加记录

使用XML编辑示例:

<?xml version="1.0" encoding="UTF-8"?>
<tester xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://tester.no/xmlSchema/xsd/tester.xsd">
  <generert>2014-12-01</generert>
  <result>
    <data>
      <id>297474</id>
      <person>
        <id>11690</id>
        <surname>Medel-Svensson</surname>
        <firstname>Ronnie</firstname>
      </person>
      <title>Title 1</title>
      <year>2009</year>
    </data>
  </result>
  <result>
    <data>
      <id>807059</id>
      <person>
        <id>11690</id>
        <surname>Bronskimlet</surname>
        <firstname>Hallstein</firstname>
      </person>
      <person>
        <id>328009</id>
        <surname>Kroksleiven</surname>
        <firstname>Jostein</firstname>
      </person>
      <person>
        <id>328010</id>
        <surname>Gassolini</surname>
        <firstname>Ruffino</firstname>
      </person>
      <person>
        <id>327990</id>
        <surname>von Schnellfahrer</surname>
        <firstname>Heinrich</firstname>
      </person>
      <title>Title 2</title>
      <year>2010</year>
      <resource>
        <type>
          <code>TEXT</code>
        </type>
        <url>http://www.example.com/</url>
      </resource>
    </data>
  </result>
  <result>
    <data>
      <id>1164653</id>
      <person>
        <id>11690</id>
        <surname>Bergsprekken</surname>
        <firstname>Mysil</firstname>
      </person>
      <title>Title 3</title>
      <year>2014</year>
      <resource>
        <type>
          <code>FULLTEKST</code>
        </type>
        <url>http://www.example.com/</url>
      </resource>
    </data>
  </result>
</tester>
有几件事:

  • 如果使用
    元素(..)
    ,则结果可能是
    null
    。如果路径中缺少元素,这可能会导致空引用异常。处理此问题的一种更优雅的方法是使用序列,如果存在元素,则使用
    SingleOrDefault()

  • XElement
    XAttribute
    都内置了一系列显式类型转换运算符。这意味着您可以强制转换为
    字符串
    和各种其他原语。由于字符串是引用类型,如果
    XObject
    为null,它将返回
    null
    。在这种情况下,
    int
    等值类型将引发异常,但
    int?
    不会

考虑到这一点,像这样的事情应该可以解决你的问题。注意:由于“数据”对所有人来说都是通用的,您可以将其放在初始选择器中:

from pubs in xElem.Elements("result").Elements("data")
select new
{
    Id = (string)pubs.Element("id"),
    Title = (string)pubs.Element("title"),
    Year = (string)pubs.Element("year"),
    Resources = (string)pubs.Elements("resource")
                            .Elements("url")
                            .SingleOrDefault(),
    Authors= pubs.Elements("person")
}

您可以使用
XPath
快速、轻松地提取数据,但您应该向我们展示XML的格式。是的,我当然可以使用XPath,但我想使用LINQ尝试一下。查尔斯干杯。我把数据放在select之前的路径中,它看起来更干净。然而,使用SingleOrDefault尝试代码仍然只返回我正在尝试的3条记录中的2条。在没有资源的情况下省略记录。是否可以包含正在解析的xml的示例?虽然我认为我可能简化了
XLinq
代码,但我认为“跳过”整个
数据
元素的问题可能与您最初尝试的代码无关。如果它试图解析缺少
资源的
数据
元素,它应该抛出异常,而不是“跳过”异常。现在添加了XML示例。好的,我已经通过
XElement.Load加载了XML。使用您的代码,我得到了一个空引用异常(正如我所期望的),使用我的代码,我得到了3项,其中一项的资源为
null
。没有理由你应该得到2。对不起,查尔斯,在最初的帖子发布后,我一定把我这边的事情搞砸了。我刚开始用你的例子来解释SingleOrDefault,这一切看起来都很有魅力!非常感谢D