Подтвердить что ты не робот

Поиск элемента в XDocument?

У меня есть простой 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"), чтобы он нашел его.

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

Требуется ли полный путь от корня?

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

Требуется ли мне для навигации XDocument знать всю структуру уровня до требуемого элемента?

4b9b3361

Ответ 1

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>

Ответ 2

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

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

где xml - это XDocument.

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

Ответ 3

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

xmlFile.Root.Elements("Band")

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

xmlFile.Descendants("Band")

Ответ 4

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

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

Ответ 5

Мой опыт работы с большими и сложными файлами 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");

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

Ответ 6

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

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

Ответ 7

Ответ Себастьяна был единственным ответом, который работал для меня во время изучения документа 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");