Почему XElement падает при анализе файла xml с помощью xmlns?

Итак, я пытаюсь разобрать файл xml:

 <?xml version="1.0" encoding="utf-8" ?>
<Root>    
  <att1 name="bob" age="unspecified" xmlns="http://foo.co.uk/nan">    
  </att1>    
</Root>

Используя следующий код:

XElement xDoc= XElement.Load(filename);
var query = from c in xDoc.Descendants("att1").Attributes() select c;
foreach (XAttribute a in query)
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}

В консоль ничего не записывается, пока я не удалю xmlns="http://foo.co.uk/nan" из файла xml, после чего я получу список имен и значений атрибутов, как и следовало ожидать, и как мне нужно !

Редактировать: Форматирование.


person zotty    schedule 11.03.2010    source источник
comment
Кстати, нет смысла писать from c in whatever select c.   -  person SLaks    schedule 11.03.2010
comment
Так нет! Спасибо :) Я взял это из очень полезного введения в LINQ to XML здесь: microsoft.com/uk/msdn/nuggets/nugget/204/   -  person zotty    schedule 11.03.2010


Ответы (3)


Вы должны использовать одно и то же пространство имен в своем коде:

XElement xDoc= XElement.Load(filename);
XNamespace ns = "http://foo.co.uk/nan";
var query = from c in xDoc.Descendants(ns + "att1").Attributes() select c;
foreach (XAttribute a in query)
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}

Атрибуты не используют пространство имен по умолчанию (xmlns=....), поэтому вам не нужно их квалифицировать. Тег пространства имен (xmln:tags=....) является чисто локальным для документа или использования API, имена действительно представляют собой пространство имен + локальное имя, поэтому вам всегда нужно указывать пространство имен.

person Richard    schedule 11.03.2010
comment
Это отлично сработало, спасибо. Поскольку пространство имен может меняться между файлами xml, я думаю, вам нужно загрузить файл в виде строки, а затем найти пространство имен и объявить его в коде? - person zotty; 11.03.2010
comment
@zotty Анализ строки не требуется, если вы запрашиваете LocalName, как показано в моем ответе. - person Lachlan Roche; 11.03.2010
comment
@zotty: Если пространства имен различаются, ваш код будет более подробным, и в нем действительно не хватает пространства имен (имя узла — пространство имен + локальное имя), но иногда это необходимо. - person Richard; 12.03.2010

Ваш вызов Потомки запрашивает элемент с именем "att1" в нет пространства имен.

Если бы вы вызвали Descendants("{http://foo.co.uk/nan}att1"), вы бы выбрали элемент с пространством имен, но не элемент без пространства имен.

Вы можете выбрать элементы с именем «att1» в любом пространстве имен или без него, например:

var query = from c in xDoc.Descendants() where c.Name.LocalName == "att1" select c.Attributes;
person Lachlan Roche    schedule 11.03.2010

Вам нужно указать пространство имен в вызове Descendants, например:

XNamespace ns = "http://foo.co.uk/nan";
foreach (XAttribute a in xDoc.Descendants(ns + "att1"))
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}
person SLaks    schedule 11.03.2010