Ошибка синтаксического анализа XDocument
Я уже несколько лет получаю доступ к базе данных через API, и сегодня были внесены изменения, но я не могу связаться с владельцами. Это, по-видимому, тонкое изменение, которое приводит к тому, что мой код дает исключение Null Reference.
Файл загружается, а затем я пытаюсь использовать 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 непригоден для использования с текущим кодом? код?
3 ответа:
Ваша проблема заключается в том, что в некоторых версиях 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 для более подробного объяснения.)При поиске элементов иерархии LINQ to XML по имени с помощью
XContainer.Element(XName)
илиXContainer.Elements(XName)
, все, что имеет значение, является ли локальным именем и пространством имен иметь требуемое локальное имя и пространство имен, используя сравнение порядковых строк.Несмотря на свое название,
XName.Get()
фактически не выполняет HTTP get или любую другую сетевую операцию. Это фабричный метод, который объединяет две строки в одну.XName
класс для сравнения перформантных равенств.Пример работы .Net fiddle .