2013-09-28 5 views
0

Xml выглядит следующим образом.Как выбрать строки в столбцы?

<System> 
    <ID></ID> 
    <Name></Name> 
    <Monitor> 
    <ID></ID> 
    <Type></Type> 
    <Alert> 
     <ID></ID> 
     <Status></Status> 
    </Alert> 
    <Alert> 
     <ID></ID> 
     <Status></Status> 
    </Alert> 
    </Monitor> 
</System> 
<System> 
    <ID></ID> 
    <Name></Name> 
    <Monitor> 
    <ID></ID> 
    <Type></Type> 
    <Alert> 
     <ID></ID> 
     <Status></Status> 
    </Alert> 
    </Monitor> 
</System> 

Я хочу, чтобы пересечь его, как этот

XElement xmlDoc = XElement.Load(@"xml"); 
var q = from el in xmlDoc.Elements("System") select el; 

foreach(el in q) { 
    Console.WriteLine(el.ID); 
    Console.WriteLine(el.Name); 

    if (el.Monitor) { 
     foreach (mon in el.Monitor) { 
      Console.WriteLine(el.ID); 
      Console.WriteLine(el.Type); 

      if (mon.Alert) { 
       foreach (alert in mon.Alert) { 
        Console.WriteLine(alert.ID); 
        Console.WriteLine(alert.Status); 
       } 
      } 
     } 
    } 
} 

В настоящее время I цикла через каждые несколько раз и использовать, если проверить поле, а затем присвоить значение переменной. Затем мне нужно снова пропустить его. Есть ли более простой способ, и я должен использовать простой LINQ или LINQ-TO-XML?

ответ

0

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()" для этой цели.

+0

Благодарим вас за ответ и объяснение. :) Принятый ответ из-за того, что он также имеет небольшое объяснение LINQ. – iskrem

0

Если вы хотите, чтобы пересечь его, как, что вы можете:

var xml = @" 
<Root> 
<System> 
<ID>1</ID> 
<Name>One</Name> 
<Monitor> 
    <ID>2</ID> 
    <Type>Two</Type> 
    <Alert> 
    <ID>3</ID> 
    <Status>Three</Status> 
    </Alert> 
    <Alert> 
    <ID>4</ID> 
    <Status>Four</Status> 
    </Alert> 
</Monitor> 
</System> 
<System> 
<ID>5</ID> 
<Name>Five</Name> 
<Monitor> 
    <ID>6</ID> 
    <Type>Six</Type> 
    <Alert> 
    <ID>7</ID> 
    <Status>Seven</Status> 
    </Alert> 
</Monitor> 
</System> 
</Root> 
"; 

XElement xmlDoc = XElement.Parse(xml); 
var q = xmlDoc.Elements("System"); 

foreach(var el in q) { 
    Console.WriteLine(el.Element("ID").Value); 
    Console.WriteLine(el.Element("Name").Value); 

    foreach(var mon in el.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); 
     } 
    } 
} 
+0

Маленькая опечатка, el.Elements («Alert») должна быть mon.Elements («Alert»). Но был ответ, который я искал. :) – iskrem

+0

@iskrem опечатка фиксированный. –

0

C# является языком ООП, я думаю, вы должны использовать, что для этого:

Пример:

public class MySystem 
{ 
    public int Id { get; private set; } 
    public string Name { get; private set; } 

    public MyMonitor[] Monitors { get; private set; } 

    public MySystem(XElement x) 
    { 
     Id = (int)x.Element("ID"); 
     Name = x.Element("Name").Value; 
     // a little confusing from your code if there can be more than one Monitor 
     Monitors = x.Elements("Monitor").Select(m => new MyMonitor(m)).ToArray(); 
    } 
} 

ли что-то подобное для своего класса монитора и оповещения класса. Я назвал его MySystem, так как класс с именем System - беспорядок.

Вы создаете свой массив систем, как я создал массив в Мониторе выше:

XElement xmlDoc = XElement.Load(@"xml"); 
MySystem[] systems = xmlDoc.Elements("System") 
          .Select(s => new MySystem(s)) 
          .ToArray(); 

Теперь у вас есть все ваши ценности в простых в использовании классов.

+0

Спасибо! Я мог бы дать сериализацию. :) – iskrem

Смежные вопросы