【问题标题】:XElement with LINQ Select and optional elements带有 LINQ Select 和可选元素的 XElement
【发布时间】:2014-12-01 12:47:02
【问题描述】:

我正在尝试从我从外部服务获得的一些 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 选择添加记录?

使用 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>

【问题讨论】:

  • 您可以使用XPath 以便快速轻松地提取数据,但您应该向我们展示 XML 的格式。
  • 是的,我当然可以使用 XPath,但我想尝试使用 LINQ。

标签: c# xml linq


【解决方案1】:

有几点:

  • 如果你使用Element(..),那么结果可能是null。如果路径中缺少元素,这可能会导致空引用异常。一种更优雅的处理方式是使用序列并使用SingleOrDefault()

  • 返回一个元素(如果存在)
  • XElementXAttribute 都内置了一组显式类型转换运算符。这意味着您可以转换为 string 和其他各种原语。由于字符串是引用类型,如果XObject 为空,它将返回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")
}

【讨论】:

  • 干杯查尔斯。我在选择之前将数据放入路径中,它看起来更干净。但是,使用 SingleOrDefault 尝试您的代码仍然只返回我正在尝试的 3 条记录中的 2 条记录。在没有资源的情况下遗漏记录。
  • 您能否包含一个您正在解析的 xml 示例?虽然我认为我可能已经简化了 XLinq 代码,但我认为“跳过”整个 data 元素的问题可能与您最初尝试的代码无关。如果它试图解析缺少resourcedata 元素,它应该抛出异常而不是“跳过”它。
  • 现在添加了 XML 示例。
  • 好的,我已经通过XElement.Load 加载了xml。使用您的代码,我得到一个空引用异常(正如我所期望的那样),并且使用我的代码,我得到 3 个项目,其中一个项目的资源为 null。没有理由你应该得到 2。
  • 对不起,查尔斯,我一定是在原帖之后搞砸了。我开始使用您的 SingleOrDefault 示例重新开始,这一切似乎都像一个魅力!非常感谢! :D
猜你喜欢
  • 1970-01-01
  • 2019-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多