【问题标题】:XElement.element() returns null sometimesXElement.element() 有时返回 null
【发布时间】:2013-01-21 21:38:14
【问题描述】:

我正在加载一个 XML 文件,获取一些节点的值,然后将这些值设置到一个对象中。

问题是,虽然我可以进入每个节点,但我无法获取它的值:它只是返回 null。在 Google 和 SO 中搜索,我发现几个线程说通常这是名称空间的问题。所以我在 XML 文件上设置了一个命名空间,并在我的代码中使用它。现在事情变得有趣了:

  • 如果除最后一个节点外的所有节点(在我的代码中)都以命名空间为前缀,则所有节点都会被设置,除了给出 ArgumentNullException 的特定节点(tabla 不接受某些属性上的空值)。这似乎是预期的行为。
  • 如果我更正了最后一行并设置了命名空间(应该如此),则会在 FIRST 节点处引发异常。

这是 XML:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://daniel.ponticelli.com/ns/dataExport">
  <PollInstance>
    <Poll_Instance_id>1</Poll_Instance_id>
    <POLL_description>Mes 1</POLL_description>
    <dt_start>01/09/2012 12:00:00 a.m.</dt_start>
    <dt_end>30/09/2012 12:00:00 a.m.</dt_end>
    <POLL_status>0</POLL_status>
    <dt_created>03/09/2012 09:50:36 a.m.</dt_created>
    <dt_updated>03/09/2012 09:50:36 a.m.</dt_updated>
    <id_original_clone>0</id_original_clone>
    <target_locs>0</target_locs>
    <id_poll>1</id_poll>
  </PollInstance>
</root>

这是最后一个元素没有命名空间的“错误”代码:

XElement instancia = xml.Descendants().First();
XNamespace ra = "http://daniel.ponticelli.com/ns/dataExport";

tabla.Poll_Instance_id = (int)instancia.Element(ra + "Poll_Instance_id");
tabla.POLL_description = (string)instancia.Element(ra + "POLL_description");
tabla.dt_start = DateTime.Parse((string)instancia.Element(ra + "dt_start"));
tabla.dt_end = DateTime.Parse((string)instancia.Element(ra + "dt_end"));
tabla.POLL_status = (int)instancia.Element(ra + "POLL_status");
tabla.dt_created = DateTime.Parse((string)instancia.Element(ra + "dt_created"));
tabla.dt_updated = DateTime.Parse((string)instancia.Element(ra + "dt_updated"));
tabla.id_original_clone = (int)instancia.Element(ra + "id_original_clone");
tabla.target_locs = (int)instancia.Element(ra + "target_locs");
tabla.id_poll = (int)instancia.Element("id_poll");

前面的代码在最后一行给出了异常。

现在这是“正确”的代码,所有元素都以命名空间为前缀:

XElement instancia = xml.Descendants().First();
XNamespace ra = "http://daniel.ponticelli.com/ns/dataExport";

tabla.Poll_Instance_id = (int)instancia.Element(ra + "Poll_Instance_id");
tabla.POLL_description = (string)instancia.Element(ra + "POLL_description");
tabla.dt_start = DateTime.Parse((string)instancia.Element(ra + "dt_start"));
tabla.dt_end = DateTime.Parse((string)instancia.Element(ra + "dt_end"));
tabla.POLL_status = (int)instancia.Element(ra + "POLL_status");
tabla.dt_created = DateTime.Parse((string)instancia.Element(ra + "dt_created"));
tabla.dt_updated = DateTime.Parse((string)instancia.Element(ra + "dt_updated"));
tabla.id_original_clone = (int)instancia.Element(ra + "id_original_clone");
tabla.target_locs = (int)instancia.Element(ra + "target_locs");
tabla.id_poll = (int)instancia.Element(ra + "id_poll");

这段代码现在在第三行给出了异常! (以tabla.Poll_Instance_id 开头的那个)。如果我在最后一行之前的“错误”代码上设置断点,我可以在 VS 中检查是否确实从 XML 中检索了值并按预期​​在对象 tabla 上设置;所以我不知道发生了什么。

【问题讨论】:

  • 所以您是说您更改了最后一行并在停止工作之前编写了几行代码?这没有任何意义,一定有其他事情发生。
  • 可能发生的唯一方法是,如果您在相同的缺少值的代码上使用不同的 XML。它不会像你声称的那样随机地神奇地失败。
  • @svick 你是对的,这没有任何意义。测试之间唯一改变的是最后一行,然后代码在之前中断了几行。
  • @JeffMercado 这不是随机的:如果你在最后一行添加命名空间,它会中断之前的 9 行;如果你不这样做,那么它就在那条线上中断。为避免干扰,我在每个测试中使用相同的 XML。
  • 好吧,它也不会因为您在后面的一行更改了名称而在该行中断。如果那条线上有问题,那么这两种情况都会在这条线上出现问题。但是,唉,它不像你说的那样......

标签: c# xml null xml-namespaces


【解决方案1】:

您的日期字符串格式无效a.m. - 使用不带点的am

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://daniel.ponticelli.com/ns/dataExport">
  <PollInstance>
    <Poll_Instance_id>1</Poll_Instance_id>
    <POLL_description>Mes 1</POLL_description>
    <dt_start>01/09/2012 12:00:00 am</dt_start>
    <dt_end>30/09/2012 12:00:00 am</dt_end>
    <POLL_status>0</POLL_status>
    <dt_created>03/09/2012 09:50:36 am</dt_created>
    <dt_updated>03/09/2012 09:50:36 am</dt_updated>
    <id_original_clone>0</id_original_clone>
    <target_locs>0</target_locs>
    <id_poll>1</id_poll>
  </PollInstance>
</root>

另外你应该在获取instancia节点时使用命名空间,或者你应该从Root xdoc.Root.Descendants().First()开始:

XNamespace ra = "http://daniel.ponticelli.com/ns/dataExport";
XElement instancia = xdoc.Descendants(ra + "PollInstance").First();

tabla.Poll_Instance_id = (int)instancia.Element(ra + "Poll_Instance_id");
tabla.POLL_description = (string)instancia.Element(ra + "POLL_description");
tabla.dt_start = ParseDate((string)instancia.Element(ra + "dt_start"));
tabla.dt_end = ParseDate((string)instancia.Element(ra + "dt_end"));
tabla.POLL_status = (int)instancia.Element(ra + "POLL_status");
tabla.dt_created = ParseDate((string)instancia.Element(ra + "dt_created"));
tabla.dt_updated = ParseDate((string)instancia.Element(ra + "dt_updated"));
tabla.id_original_clone = (int)instancia.Element(ra + "id_original_clone");
tabla.target_locs = (int)instancia.Element(ra + "target_locs");
tabla.id_poll = (int)instancia.Element(ra + "id_poll");

并使用 ParseExact 以您的格式解析日期

static DateTime ParseDate(string s)
{
    return DateTime.ParseExact(s, "dd/MM/yyyy hh:mm:ss tt",
                               CultureInfo.InvariantCulture);
}

如果您无法更改 xml 的数据格式,请更新,然后只需执行 String.Replacea.m. 更改为 am

static DateTime ParseDate(string s)
{
    string dateString = s.Replace("a.m.", "AM").Replace("p.m.", "PM");
    return DateTime.ParseExact(dateString, 
          "dd/MM/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture);
}

【讨论】:

  • 不要编辑 XML 以将所有 a.m. 更改为 am,而是在将值从 XML 中提取出来之后,再将它们转换为 DateTime.,对这些值使用字符串 Replace(".", "") 方法
  • @ChuckSavage 同意,这也是解决方案。取决于谁在创建这些 xml。如果是 OP,那么我认为最好更改写入 xml 的数据格式。如果他只是阅读,那么,字符串替换将完成这项工作
  • @lazyberezovsky 正在解析日期 好的。即使评论加载日期的行,问题仍然存在。我会尝试一下你在命名空间和根节点上的说法。
【解决方案2】:

我找到了解决方案,感谢@lazyberezovsky 用 root() 为我指明了正确的方向。

问题出在Descendants() 方法上,它给了我所有的后代节点;所以我得到了 PollInstance 节点以及Poll_instance_id 和其他节点。这就是它在“正确”代码的第一行中断的原因:在处理第一个节点后,它在其他节点上阻塞。

相反,我必须使用Elements() 方法,它只返回直接子节点;就我而言,只有PollInstance

【讨论】:

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