Разбор XML файла с использованием С#?

Я новичок в XML и С#; Я пытаюсь найти способ эффективно разобрать данный XML файл для получения соответствующих числовых значений, основываясь на значении "proj_title" = heat_run или любых других возможных значениях. Например, вычисление продолжительности конкретного тестового прогона (proj_end val-proj_start val).

ex.xml:

<proj ID="2">
      <proj_title>heat_run</proj_title>
      <proj_start>100</proj_start>
      <proj_end>200</proj_end>
</proj>

... Мы не можем выполнить поиск по идентификатору proj, так как это значение не фиксируется из тестового прогона в тестовый прогон. Вышеупомянутый файл огромен: ~ 8mb, а там ~ 2000 тегов с именем proj_title. есть эффективный способ сначала найти все имена тегов w/proj_title= "heat_run", затем получить начальное и конечное значение proj для этого конкретного proj_title с помощью С#??

Здесь мой текущий код С#:

public class parser
{
     public static void Main()
     {
         XmlDocument xmlDoc= new XmlDocument();
         xmlDoc.Load("ex.xml");

         //~2000 tags w/ proj_title
         //any more efficient way to just look for proj_title="heat_run" specifically?
         XmlNodeList heat_run_nodes=xmlDoc.GetElementsByTagName("proj_title");
     }
}    

Ответ 1

Вы можете использовать XPath для поиска всех узлов, которые соответствуют, например:

XmlNodeList matches = xmlDoc.SelectNodes("proj[proj_title='heat_run']")

matches будет содержать все узлы proj, которые соответствуют критерию. Подробнее о XPath: http://www.w3schools.com/xsl/xpath_syntax.asp

Документация MSDN на SelectNodes

Ответ 2

8MB действительно не очень велик по современным стандартам. Лично я бы использовал LINQ для XML:

XDocument doc = XDocument.Load("ex.xml");
var projects = doc.Descendants("proj_title")
                  .Where(x => (string) x == "heat_run")
                  .Select(x => x.Parent) // Just for simplicity
                  .Select(x => new {
                              Start = (int) x.Element("proj_start"),
                              End = (int) x.Element("proj_end")
                          });

foreach (var project in projects)
{
    Console.WriteLine("Start: {0}; End: {1}", project.Start, project.End);
}

(Очевидно, приспособите это к вашим собственным требованиям - это не совсем понятно, что вам нужно делать на основе вопроса.)

Альтернативный запрос:

var projects = doc.Descendants("proj")
                  .Where(x => (string) x.Element("proj_title") == "heat_run")
                  .Select(x => new {
                              Start = (int) x.Element("proj_start"),
                              End = (int) x.Element("proj_end")
                          });

Ответ 3

Используйте XDocument и используйте LINQ api. http://msdn.microsoft.com/en-us/library/bb387098.aspx

Если производительность не такая, как вы ожидаете, попробовав ее, вы должны искать парсер для сакса. Парсер Sax не будет загружать весь документ в память и попытаться применить выражение xpath во всем в памяти. Он работает больше в режиме, основанном на событиях, и в некоторых случаях это может быть намного быстрее и не использует столько памяти.

Есть, вероятно, саксофоризаторы для .NET там, они не использовали их для .NET, но я сделал для С++.