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;
}
}
}
这里有一些东西。
- 正如 Martin Honnen 指出的那样,您正在使用
XElement.Parse
。这意味着 root
在您的情况下 是 Message
并且不会有该名称的子元素。
- 您正在正确使用命名空间来获取路由代码,但您忽略了它们来填充
UserDTO
。例如,名称应为 ns + Params
和 ns2 + User
.
- 用户名是属性,而不是元素。
我要提出的另一个建议是不要早 '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。
我有一个 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;
}
}
}
这里有一些东西。
- 正如 Martin Honnen 指出的那样,您正在使用
XElement.Parse
。这意味着root
在您的情况下 是Message
并且不会有该名称的子元素。 - 您正在正确使用命名空间来获取路由代码,但您忽略了它们来填充
UserDTO
。例如,名称应为ns + Params
和ns2 + User
. - 用户名是属性,而不是元素。
我要提出的另一个建议是不要早 '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。