Находить элемент в XDocument? - PullRequest
49 голосов
/ 11 декабря 2011

У меня есть простой XML

<AllBands>
  <Band>
    <Beatles ID="1234" started="1962">greatest Band<![CDATA[lalala]]></Beatles>
    <Last>1</Last>
    <Salary>2</Salary>
  </Band>
  <Band>
    <Doors ID="222" started="1968">regular Band<![CDATA[lalala]]></Doors>
    <Last>1</Last>
    <Salary>2</Salary>
  </Band>
</AllBands>

Тем не менее,

, когда я хочу добраться до "группы дверей" и изменить ее ID:

  using (var stream = new StringReader(result))
            {
                XDocument xmlFile = XDocument.Load(stream);

                var query = from c in xmlFile.Elements("Band")

                            select c;
                             ...

query не имеет результатов

Но

Если я напишу xmlFile.Elements().Elements("Band"), значит он его найдет.

В чем проблема?

Необходим ли полный путь от Root?

И если да, то почему он работает без указания AllBands?

Требуется ли для навигации XDocument, чтобы я зналполная структура уровня до требуемого элемента?

Ответы [ 7 ]

76 голосов
/ 11 декабря 2011

Elements() будет проверять только прямые дочерние элементы - который в первом случае является корневым элементом, а во втором случае дочерними элементами корневого элемента, следовательно, вы получите совпадение во втором случае.Если вы просто хотите, чтобы любой соответствующий потомок использовал Descendants() вместо:

var query = from c in xmlFile.Descendants("Band") select c;

Также я бы предложил вам реструктурировать ваш XML: имя группы должно быть значением атрибута или элемента, а не самого имени элемента -это делает запрос (и проверку схемы в этом отношении) намного сложнее, то есть что-то вроде этого:

<Band>
  <BandProperties Name ="Doors" ID="222" started="1968" />
  <Description>regular Band<![CDATA[lalala]]></Description>
  <Last>1</Last>
  <Salary>2</Salary>
</Band>
27 голосов
/ 18 января 2013

Вы можете сделать это следующим образом:

xml.Descendants().SingleOrDefault(p => p.Name.LocalName == "Name of the node to find")

, где xml - это XDocument.

Имейте в виду, что свойство Name возвращает объект, имеющий LocalName и пространство имен.Вот почему вы должны использовать Name.LocalName, если вы хотите сравнить по имени.

25 голосов
/ 11 декабря 2011

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

xmlFile.Root.Elements("Band")

Если вы хотите найти элементы в любом месте документа, используйте Descendants вместо:

xmlFile.Descendants("Band")
6 голосов
/ 11 декабря 2011

Проблема в том, что Elements принимает только прямые дочерние элементы того, что вы вызываете. Если вы хотите, чтобы все потомки использовали метод Descendants:

var query = from c in xmlFile.Descendants("Band")
4 голосов
/ 23 августа 2017

Мой опыт работы с большими и сложными XML-файлами заключается в том, что иногда ни Элементы, ни Потомки, кажется, не работают при извлечении определенного Элемента (и я до сих пор не знаю почему).

В таких случаях я обнаружил, что гораздо более безопасным вариантом является поиск элемента вручную, как описано в следующем сообщении MSDN:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/3d457c3b-292c-49e1-9fd4-9b6a950f9010/how-to-get-tag-name-of-xml-by-using-xdocument?forum=csharpgeneral

Короче говоря, вы можете создать функцию GetElement:

private XElement GetElement(XDocument doc,string elementName)
{
    foreach (XNode node in doc.DescendantNodes())
    {
        if (node is XElement)
        {
            XElement element = (XElement)node;
            if (element.Name.LocalName.Equals(elementName))
                return element;
        }
    }
    return null;
}

Который вы можете затем назвать так:

XElement element = GetElement(doc,"Band");

Обратите внимание, что это вернет ноль , если соответствующий элемент не найден.

2 голосов
/ 11 декабря 2011

Метод Elements() возвращает IEnumerable<XElement>, содержащий все дочерние элементы текущего узла. Для XDocument эта коллекция содержит только элемент Root. Поэтому требуется следующее:

var query = from c in xmlFile.Root.Elements("Band")
            select c;
0 голосов
/ 14 декабря 2018

Ответ Себастьяна был единственным ответом, который работал для меня при изучении документа xaml. Если, как и я, вам нужен список всех элементов, то этот метод будет очень похож на ответ Себастьяна выше, но просто возвращает список ...

    private static List<XElement> GetElements(XDocument doc, string elementName)
    {
        List<XElement> elements = new List<XElement>();

        foreach (XNode node in doc.DescendantNodes())
        {
            if (node is XElement)
            {
                XElement element = (XElement)node;
                if (element.Name.LocalName.Equals(elementName))
                    elements.Add(element);
            }
        }
        return elements;
    }

Назовите это так:

var elements = GetElements(xamlFile, "Band");

или в случае моего документа xaml, где я хотел получить все текстовые блоки, назовите его так:

var elements = GetElements(xamlFile, "TextBlock");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...