Ok попробуйте этот код (см ниже код для объяснений)
class Program {
static void Main(string[] args) {
var xml = @"
<Root>
<System>
<ID>1</ID>
<Name>one</Name>
<Monitor>
<ID>3</ID>
<Type>t3</Type>
<Alert>
<ID>5</ID>
<Status>a5</Status>
</Alert>
<Alert>
<ID>6</ID>
<Status>a6</Status>
</Alert>
</Monitor>
</System>
<System>
<ID>2</ID>
<Name>two</Name>
<Monitor>
<ID>4</ID>
<Type>t4</Type>
<Alert>
<ID>7</ID>
<Status>a7</Status>
</Alert>
</Monitor>
</System>
</Root>
";
XElement xmlDoc = XElement.Parse(xml);
// set q to an enumeration of XElements
// where the elements xname is "System"
// the query actually executes the first time q is used
var q = xmlDoc.Elements("System");
foreach (var ele in q) {
// Get the value of the Element with the xname of "ID"
Console.WriteLine(ele.Element("ID").Value);
Console.WriteLine(ele.Element("Name").Value);
// if ele.Elements("Monitor") returns nothing
// then the foreach will be skipped (null-execution)
foreach (var mon in ele.Elements("Monitor")) {
Console.WriteLine(mon.Element("ID").Value);
Console.WriteLine(mon.Element("Type").Value);
foreach (var alert in mon.Elements("Alert")) {
Console.WriteLine(alert.Element("ID").Value);
Console.WriteLine(alert.Element("Status").Value);
}
}
}
}
}
Этот код будет перемещаться по документу XML ровно один раз , В C# LINQ содержатся оба языковых элемента (например, «select» и «from») и элемент библиотеки (методы .NET Framework, такие как XDocument.Elements); смешивание двух в порядке, но это должно быть сделано только с пониманием того, что происходит за заявлениями. В этом случае вы просите XDocument вернуть все дочерние элементы с помощью XName «System». В приведенном выше коде «q» не получает все элементы, он получает перечисление, которое может быть итерировано. Назначение q - операция с очень низкой стоимостью, потому что содержимое XDocument не является поперечным до тех пор, пока не будет проверен первый foreach, а затем только один элемент за раз. Сделайте поиск «Возврат к возврату C#», чтобы узнать, как это реализовано.
Если вы были заинтересованы только в элементах «Alert» вы могли бы сделать что-то вроде этого:
var alerts = xmlDoc.Descendants("Alert")
Это возвратит перечисление всех элементов с XName из «Alert» (независимо от того, где они находятся в иерархии XML-документа). Если вы хотите, чтобы обеспечить иерархию вы можете использовать «где», например:
var alerts = xmlDoc.Descendants("Alert")
.Where(ele => (ele.Parent != null) && (ele.Parent.Name == "Monitor"))
.Where(ele => (ele.Parent.Parent != null) && (ele.Parent.Parent.Name == "System"));
foreach (var alert in alerts) {
Console.WriteLine(alert.Element("ID").Value);
Console.WriteLine(alert.Element("Status").Value);
}
Если вам нужно перебрать те же узлы несколько раз, вы должны рассмотреть вопрос о преобразовании перечисления в список или массив, это экономит время но увеличивает использование памяти. IEnumerable <> имеет методы расширения ".ToArray()" и ".ToList()" для этой цели.
Благодарим вас за ответ и объяснение. :) Принятый ответ из-за того, что он также имеет небольшое объяснение LINQ. – iskrem