XML:XElement.Parse 正在抛出异常

XML: XElement.Parse is Throwing an Exception

我有一个 xml 字符串列表,我需要解析这些字符串并将其加载到 c# class 中。我收到空引用异常,并认为 "root" 原因是 xml 中使用的名称空间。我不太精通xml,所以如果这个解决方案看起来很糟糕,请提供替代方案。

解析代码如下:

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>

如果您使用 XElement.Parse 而不是 XDocument.Parse,那么您的 root 元素就是 Message 元素,任何选择的子元素都应该以 Params 开头元素。

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

尝试使用此代码检索属性。

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"))
                     });

尝试将命名空间链接到 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;

        }
    }
}​

这里有一些东西。

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

我要提出的另一个建议是不要早 'leave the monad'。使用 return 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