2016-12-08 3 views
2

Я пишу свою собственную программу навигации по карте C#. Я использую OpenStreetMaps для данных карты. Это большой XML-файл, содержащий узлы и способы. Я написал конвертер, который удаляет XML-файл из бесполезного мусора (например, timestamp, user и т. Д.), Поэтому файл станет меньше.Усиление сложности анализа XML - C# XML Looping

Теперь, когда я пытаюсь пересечь XML и преобразовывать данные в объект C# Пути и узлы, я столкнулся с проблемой. Мне нужно сделать так много циклов, что время загрузки слишком длинное.

Пример XML (W = путь, п ​​= узла, RF = ссылкой на узел):

 <n id="2638006578" l="5.9295547" b="52.5619519" /> 
     <n id="2638006579" l="5.9301973" b="52.5619526" /> 
     <n id="2638006581" l="5.9303625" b="52.5619565" /> 
     <n id="2638006583" l="5.9389539" b="52.5619577" /> 
     <n id="2638006589" l="5.9386643" b="52.5619733" /> 
     <n id="2638006590" l="5.9296231" b="52.5619760" /> 
     <n id="2638006595" l="5.9358987" b="52.5619864" /> 
     <n id="2638006596" l="5.9335913" b="52.5619865" /> 
     <w id="453071384"> 
     <nd rf="2638006581" /> 
     <nd rf="2638006590" /> 
     <nd rf="2638006596" /> 
     <nd rf="2638006583" /> 
     <nd rf="2638006578" /> 
     </w> 
     <w id="453071385"> 
     <nd rf="2638006596" /> 
     <nd rf="2638006578" /> 
     <nd rf="2638006581" /> 
     <nd rf="2638006583" /> 
     </w> 
  • Путь узлы содержат ссылки на узлы, так что узел может быть существует в несколько путей (узлы соединяют пути).

  • Узлы содержат долготу и широту (l = lon, b = lat).

  • Эти файлы XML содержат узлов и путей, поэтому это не просто небольшой файл. Файл XML в приведенном ниже примере кода имеет 500K строк.

Мой код

class Program { 

     static List<Way> ways = new List<Way>(); 
     static List<Node> nodes = new List<Node>(); 

     static void Main(String[] args) { 
      read(); 
     } 
     public static void read() { 
      String xmlLoc = @"C:\Users\MyName\Desktop\result.xml"; 
      long time = DateTime.Now.Ticks; 
      Parse(xmlLoc); 
      long time2 = DateTime.Now.Ticks; 
      Console.WriteLine("Done: {0} ms", (time2 - time)/10000); 
      Console.WriteLine(" - Nodes Amount:" + nodes.Count()); 
      Console.WriteLine(" - Ways Amount: " + ways.Count()); 
     } 

     private static Node GetByRef(long reference) { 
      return nodes.First(x => x.ID == reference); 
     } 

     private static void Parse(string path) { 
      using (XmlReader reader = XmlReader.Create(path)) { 
       reader.MoveToContent(); 
       while (reader.Read()) { 
        if (reader.NodeType == XmlNodeType.Element) { 
         XElement element = XElement.ReadFrom(reader) as XElement; 
         if (element.Name.ToString().Equals("w")) { 
          Way w = new Way(); 
          var name = element.Attribute("nm"); 
          if (name != null) w.Name = name.Value; 
          var children = element.Descendants("nd"); 
          foreach (XElement child in children) w.References.Add(long.Parse(child.Attribute("rf").Value)); 
          ways.Add(w); 
         }else if (element.Name.ToString().Equals("n")) { 
          Node n = new Node(); 
          n.ID = long.Parse(element.Attribute("id").Value); 
          n.Lon = double.Parse(element.Attribute("l").Value); 
          n.Lat = double.Parse(element.Attribute("b").Value); 
          nodes.Add(n); 
         } 
        } 
       } 
      } 
     } 
    } 

    class Way { 

     public List<long> References { get; private set; } 
     public long ID { get; set; } 
     public String Name { get; set; } 
     public bool OneWay { get; set; } 

     public Way() { 
      this.References = new List<long>(); 
     } 
    } 

    class Node { 
     public long ID { get; set; } 
     public double Lat { get; set; } 
     public double Lon { get; set; } 
    } 

В настоящее время не существует действительное отношение между классом Пути и класса Node. Есть только список с long значениями. Мне почему-то нужно добавить список с узлами в класс Way, но это потребует от меня работы с другим (два?) Для/while циклов. Это будет означать O (N4), я считаю, что это медленно.

Технически я ищу и решение, и способы построить это лучше, если вы посоветуете, я бы хотел его услышать!

Заранее благодарен!

PS: Если мне нужно обновить/изменить свой вопрос, пожалуйста, скажите мне, а не немедленно.

+1

Рассмотрим встроенный XML десериализации вместо того, чтобы писать собственный анализатор. Первый пример среди многих других: http://stackoverflow.com/questions/364253/how-to-deserialize-xml-document – Tomalak

+0

Действительно ли необходимо циклически перебирать XML-файл более одного раза? Как насчет того, чтобы делать только один проход и * хранить * все необходимое позже? – scai

+0

@Tomalak Я загляну в него, спасибо! – Dubb

ответ

0

Использование XML LINQ

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data; 
using System.Xml; 
using System.Xml.Linq; 
using System.IO; 


namespace ConsoleApplication31 
{ 
    class Program 
    { 
     const string FILENAME = @"c:\temp\test.xml"; 
     static void Main(string[] args) 
     { 

      XDocument xdoc = XDocument.Load(FILENAME); 

      var results = xdoc.Elements("root").Select(x => new 
      { 
       ns = x.Descendants("n").Select(y => new { 
        id = (long)y.Attribute("id"), 
        l = (double)y.Attribute("l"), 
        b = (double)y.Attribute("b") 
       }).ToList(), 
       ws = x.Descendants("w").Select(y => new { 
        id = (long)y.Attribute("id"), 
        rfs= y.Descendants("nd").Select(z => (long)z.Attribute("rf")).ToList() 
       }).ToList() 
      }).FirstOrDefault(); 

     } 
    } 

} 
+0

Эй, спасибо за ваш ответ. Однако проблема состоит в том, что ссылки являются списком длинных значений. Мне нужны ссылки, чтобы быть точными узлами из списка узлов. Значение длинной ссылки совпадает с ID из узла в списке узлов. @jdweng – Dubb

+0

Не уверен, что вы имеете в виду. Для тега nd у меня есть один id с массивом значений rf. Ссылка на список длинных значений - это массив длинных целых чисел. – jdweng