Ошибка разбора 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 не подходит для текущего кода?
2 ответа
Ваша проблема в том, что в некоторых версиях 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 скрипки.
Это может быть вызвано поиском элемента, который на самом деле не существует в XML.
В этом случае будет сгенерировано исключение ссылки Null. Если изменение было сделано в самом XML, то это может быть причиной ошибки.
XName.Get
возвращает объект XName, который является нулевым, потому что URL http://www.clublog.org/cty/v1.0
возвращает ошибку 404 Единственный способ исправить это - найти местоположение нового URL.