2015-11-10 53 views
0

我有一个需要解析并加载到c#类中的xml字符串列表。我收到空引用异常,并认为它的“根”原因是在xml中使用的命名空间。我不熟悉ling到xml,所以如果这个解决方案看起来不好,请提供替代方案。XML:XElement.Parse正在抛出异常

这里的解析代码:

XNamespace ns = "http://www.example.com/schema/msc/message"; 
XNamespace ns2 = "http://www.example.com/schema/msc/referral"; 

// data is List<string> 
Parallel.ForEach(data, item => 
{ 
    var root = XElement.Parse(item); 
    var dto = new DTO 
     { 
     RoutingCode = (string)root.Element("Message") 
       .Element(ns + "Params") 
       .Element(ns + "Events") 
       .Attribute("Code") 
     User = new UserDTO 
        { 
        AccountName = (string)root.Element("Message") 
            .Element("Params") 
            .Element("Events") 
            .Element("ref:User") 
            .Element("Name") 
        } 
     }; 
    list.Add(dto); 
}); 

下面是一个示例XML元素(减小尺寸的可读性)

<Message xmlns="http://www.example.com/schema/msc/message"> 
    <Params> 
    <Events xmlns="http://www.example.com/schema/msc/referral" Code="AC"> 
     <ref:User xmlns:ref="http://www.example.com/schema/msc/referral" Name="asdf"/> 
    </Events> 
    </Parama> 
</Message> 

回答

1

这里有几件事情。

  1. 正如Martin Honnen指出的,您正在使用XElement.Parse。这意味着您的案例中的rootMessage并且不会有该名称的子元素。
  2. 您正在正确使用名称空间来获取路由代码,但是您忽略它们以填充UserDTO。名称应该是,例如,ns + Paramsns2 + User
  3. 用户的名字是属性,而不是元素

我想提出的另一个建议是不要提前离开monad。使用返回IEnumerable<T>的方法,直到不必。所以更喜欢root.Elements(ns + "Params").Elements(ns + "Events").SingleOrDefault()root.Element(ns + "Params").Element(ns +"Events")。这避免了空引用异常。

把所有这些组合起来,我们得到这样的:

XNamespace message = "http://www.example.com/schema/msc/message"; 
XNamespace referral = "http://www.example.com/schema/msc/referral"; 

var root = XElement.Parse(xml); 

var dto = new 
{ 
    RoutingCode = (string) root.Elements(message + "Params") 
     .Elements(referral + "Events") 
     .Attributes("Code") 
     .Single(), 
    User = new 
    { 
     AccountName = (string) root.Elements(message + "Params") 
      .Elements(referral + "Events") 
      .Elements(referral + "User") 
      .Attributes("Name") 
      .Single() 
    } 
}; 

的工作示例见this fiddle

1

如果使用XElement.Parse而不是XDocument.Parse那么你root元素是Message元素任何选择的孩子都应该从Params元素开始。

 RoutingCode = (string)root.Element(ns + "Params") 
      .Element(ns2 + "Events") 
      .Attribute("Code") 
+0

这是有道理的,但我仍然得到例外。任何方式我可以更好地获取调试信息,而不是捕获异常? –

0

试试这个代码来检索属性。

var doc = XDocument.Parse(xml); 

XNamespace ns = "http://www.example.com/schema/msc/referral"; 

doc.Descendants(ns + "Events") 
    .Select(e => new DTO { 
          RoutingCode = (string)e.Attribute("Code"), 
          User = new UserDTO((string)e.Element(ns + "User").Attribute("Name")) 
        }); 
0

尝试命名空间链接到的XElement

using System; 
 
using System.Collections.Generic; 
 
using System.Linq; 
 
using System.Text; 
 
using System.Xml; 
 
using System.Xml.Linq; 
 

 
namespace ConsoleApplication1 
 
{ 
 
    class Program 
 
    { 
 
     static void Main(string[] args) 
 
     { 
 
      string item = 
 
       "<Message xmlns=\"http://www.example.com/schema/msc/message\">" + 
 
        "<Params>" + 
 
        "<Events xmlns=\"http://www.example.com/schema/msc/referral\" Code=\"AC\">" + 
 
         "<ref:User xmlns:ref=\"http://www.example.com/schema/msc/referral\" Name=\"asdf\"/>" + 
 
        "</Events>" + 
 
        "</Params>" + 
 
       "</Message>"; 
 

 
      XElement root = XElement.Parse(item); 
 
      XNamespace ns1 = root.Name.Namespace; 
 
      XNamespace ns2 = root.Descendants().Where(x => x.Name.LocalName == "Events").FirstOrDefault().Name.Namespace; 
 

 
     } 
 
    } 
 
}​