Поиск элемента в 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
знать всю структуру уровня до требуемого элемента?
Ответы
Ответ 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");