XDocument 解析错误
XDocument parsing error
多年来我一直通过 API 访问数据库,今天进行了更改,但我无法联系所有者。这似乎是一个微妙的变化,导致我的代码给出空引用异常。
下载了一个文件,然后我尝试使用 XmlReader
并使用以下代码将其加载到字典中:
Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
using (var file = File.Open(dir + @"\dxcc_matrix.gz", FileMode.Open))
{
using (var zip = new GZipStream(file, CompressionMode.Decompress))
{
using (var xmlReader = XmlReader.Create(zip))
{
var xd = XDocument.Load(xmlReader);
dict = //error occurs here
xd
.Document
.Root
.Element(XName.Get("entities", "http://www.clublog.org/cty/v1.0"))
.Elements(XName.Get("entity", "http://www.clublog.org/cty/v1.0"))
.ToDictionary(
x => (decimal)x.Element(XName.Get("adif", "http://www.clublog.org/cty/v1.0")),
x => x.Element(XName.Get("name", "http://www.clublog.org/cty/v1.0")).Value);
}
}
}
部分 XML 文件如下所示:
<clublog date="2018-02-13T21:30:11+00:00"
xmlns="https://clublog.org/cty/v1.0">
<entities>
<entity>
<adif>1</adif>
<name>CANADA</name>
<prefix>VE</prefix>
<deleted>FALSE</deleted>
<cqz>5</cqz>
<cont>NA</cont>
<long>-80.00</long>
<lat>45.00</lat>
</entity>
<entity>
<adif>2</adif>
<name>ABU AIL IS</name>
<prefix>A1</prefix>
<deleted>TRUE</deleted>
<cqz>21</cqz>
<cont>AS</cont>
<long>45.00</long>
<lat>12.80</lat>
<end>1991-03-30T23:59:59+00:00</end>
</entity>
<!--Additional entities omitted-->
</entities>
</clublog>
是不是我的代码突然出了什么问题,还是 XML 无法与当前代码一起使用?
这可能是由于搜索了 XML 中实际不存在的元素造成的。
在这种情况下,将抛出Null 引用异常。如果更改是在 XML 本身进行的,那么这很可能是错误原因。
您的问题是,在 XML 的某些版本中,<entity>
和 <entities>
元素位于 "http://www.clublog.org/cty/v1.0"
XML 命名空间中,但是在其他情况下,它们位于 "https://clublog.org/cty/v1.0"
命名空间中。
为了解析任一 XML 版本,您需要检查您的元素是否在两个可能的命名空间中的任何一个中,例如使用以下方法:
public static class AdifDictionaryExtensions
{
public static Dictionary<decimal, string> ExtractAdifDictionary(TextReader reader)
{
Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
using (var xmlReader = XmlReader.Create(reader))
{
var xd = XDocument.Load(xmlReader);
var ns1 = (XNamespace)"http://www.clublog.org/cty/v1.0";
var ns2 = (XNamespace)"https://clublog.org/cty/v1.0";
dict =
xd
.Root
.Elements("entities", ns1, ns2).Single()
.Elements("entity", ns1, ns2)
.ToDictionary(
x => (decimal)x.Elements("adif", ns1, ns2).Single(),
x => x.Elements("name", ns1, ns2).Single().Value);
return dict;
}
}
}
public static class XContainerExtensions
{
public static IEnumerable<XElement> Elements(this XContainer container, string localName, XNamespace nameSpace, params XNamespace[] additionalNamespaces)
{
if (container == null || localName == null)
throw new ArgumentNullException();
var names = new[] { nameSpace }.Concat(additionalNamespaces).Select(ns => ns + localName).ToArray();
return container.Elements().Where(e => names.Any(n => n == e.Name));
}
}
备注:
您可能会认为 XML 命名空间 "http://www.clublog.org/cty/v1.0"
和 "https://clublog.org/cty/v1.0"
是可能会或可能不会解析为相同地址的实际 URL。然而,从 XML 解析的角度来看,这些名称空间只是字符串,当组合到大型异构 XML 文档中时,这些名称空间有助于提供元素和属性的唯一命名。 (有关更多说明,请参阅 XML namespace。)
当使用 XContainer.Element(XName)
or XContainer.Elements(XName)
, all that matters is whether the local name and namespace 按名称搜索 LINQ to XML 层次结构时,使用序号字符串比较具有所需的本地名称和命名空间。
尽管它的名字,XName.Get()
doesn't actually perform an http get or any other network operation. It is a factory method that combines two strings into an XName
class 用于性能平等比较。
工作示例 .Net fiddle。
多年来我一直通过 API 访问数据库,今天进行了更改,但我无法联系所有者。这似乎是一个微妙的变化,导致我的代码给出空引用异常。
下载了一个文件,然后我尝试使用 XmlReader
并使用以下代码将其加载到字典中:
Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
using (var file = File.Open(dir + @"\dxcc_matrix.gz", FileMode.Open))
{
using (var zip = new GZipStream(file, CompressionMode.Decompress))
{
using (var xmlReader = XmlReader.Create(zip))
{
var xd = XDocument.Load(xmlReader);
dict = //error occurs here
xd
.Document
.Root
.Element(XName.Get("entities", "http://www.clublog.org/cty/v1.0"))
.Elements(XName.Get("entity", "http://www.clublog.org/cty/v1.0"))
.ToDictionary(
x => (decimal)x.Element(XName.Get("adif", "http://www.clublog.org/cty/v1.0")),
x => x.Element(XName.Get("name", "http://www.clublog.org/cty/v1.0")).Value);
}
}
}
部分 XML 文件如下所示:
<clublog date="2018-02-13T21:30:11+00:00"
xmlns="https://clublog.org/cty/v1.0">
<entities>
<entity>
<adif>1</adif>
<name>CANADA</name>
<prefix>VE</prefix>
<deleted>FALSE</deleted>
<cqz>5</cqz>
<cont>NA</cont>
<long>-80.00</long>
<lat>45.00</lat>
</entity>
<entity>
<adif>2</adif>
<name>ABU AIL IS</name>
<prefix>A1</prefix>
<deleted>TRUE</deleted>
<cqz>21</cqz>
<cont>AS</cont>
<long>45.00</long>
<lat>12.80</lat>
<end>1991-03-30T23:59:59+00:00</end>
</entity>
<!--Additional entities omitted-->
</entities>
</clublog>
是不是我的代码突然出了什么问题,还是 XML 无法与当前代码一起使用?
这可能是由于搜索了 XML 中实际不存在的元素造成的。
在这种情况下,将抛出Null 引用异常。如果更改是在 XML 本身进行的,那么这很可能是错误原因。
您的问题是,在 XML 的某些版本中,<entity>
和 <entities>
元素位于 "http://www.clublog.org/cty/v1.0"
XML 命名空间中,但是在其他情况下,它们位于 "https://clublog.org/cty/v1.0"
命名空间中。
为了解析任一 XML 版本,您需要检查您的元素是否在两个可能的命名空间中的任何一个中,例如使用以下方法:
public static class AdifDictionaryExtensions
{
public static Dictionary<decimal, string> ExtractAdifDictionary(TextReader reader)
{
Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
using (var xmlReader = XmlReader.Create(reader))
{
var xd = XDocument.Load(xmlReader);
var ns1 = (XNamespace)"http://www.clublog.org/cty/v1.0";
var ns2 = (XNamespace)"https://clublog.org/cty/v1.0";
dict =
xd
.Root
.Elements("entities", ns1, ns2).Single()
.Elements("entity", ns1, ns2)
.ToDictionary(
x => (decimal)x.Elements("adif", ns1, ns2).Single(),
x => x.Elements("name", ns1, ns2).Single().Value);
return dict;
}
}
}
public static class XContainerExtensions
{
public static IEnumerable<XElement> Elements(this XContainer container, string localName, XNamespace nameSpace, params XNamespace[] additionalNamespaces)
{
if (container == null || localName == null)
throw new ArgumentNullException();
var names = new[] { nameSpace }.Concat(additionalNamespaces).Select(ns => ns + localName).ToArray();
return container.Elements().Where(e => names.Any(n => n == e.Name));
}
}
备注:
您可能会认为 XML 命名空间
"http://www.clublog.org/cty/v1.0"
和"https://clublog.org/cty/v1.0"
是可能会或可能不会解析为相同地址的实际 URL。然而,从 XML 解析的角度来看,这些名称空间只是字符串,当组合到大型异构 XML 文档中时,这些名称空间有助于提供元素和属性的唯一命名。 (有关更多说明,请参阅 XML namespace。)当使用
XContainer.Element(XName)
orXContainer.Elements(XName)
, all that matters is whether the local name and namespace 按名称搜索 LINQ to XML 层次结构时,使用序号字符串比较具有所需的本地名称和命名空间。尽管它的名字,
XName.Get()
doesn't actually perform an http get or any other network operation. It is a factory method that combines two strings into anXName
class 用于性能平等比较。
工作示例 .Net fiddle。