2017-02-09 12 views
2

У меня есть много файлов .xsd для многих схем XMLНаиболее эффективный способ, чтобы определить, как использовать класс для десериализации XML

например

XML 1.0 - xml_1_0.xml

<?xml version="1.0" encoding="UTF-8"?> 
    <cars version="1.00"> 
     <car>Honda</car> 
     <car>Ferrari</car> 
    </cars> 

XML 2,0 - xml_2_0.xml

<?xml version="1.0" encoding="UTF-8"?> 
<cars version="2.00"> 
    <car> 
     <name>Honda</name> 
     <color>White</color> 
    </car> 

    <car> 
     <name>Honda</name> 
     <color>Red</color> 
    </car> 
</cars> 

Я создаю свои классы из XSD-как этот

xsd.exe cars_1_0.xsd /c 

xsd.exe cars_2_0.xsd /c 

И Deserialize так:

foreach(string file in files) { 
    XmlDocument doc = new XmlDocument(); 
    doc.Load(file);  
    string version = doc.SelectSingleNode("/Cars/@version").Value; 

    if(version == "1.00") 
    { 
     Stream reader = new FileStream(file, FileMode.Open); 
     XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars)); 

     v1.Cars XML = new v1.Cars(); 
     XML = (v1.Cars)serializer.Deserialize(reader); 
    } 
    else if(version == "2.00") 
    { 
     Stream reader = new FileStream(file, FileMode.Open); 
     XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars)); 

     v2.Cars XML = new v2.Cars(); 
     XML = (v2.Cars)serializer.Deserialize(reader); 
    } 
} 

Кто-нибудь знает лучший способ сделать это, или иметь более высокую производительность?

+0

Вы можете поделиться фактическим XSD? Изменяет XSD вариант? Создает ли новый класс вариант? –

+0

в quetion я написал только пример, файлы xsd намного сложнее, и любая версия xml имеет много других атрибутов –

ответ

1

У вас есть несколько вариантов, в зависимости от того, насколько вы хотите это сделать. Одним довольно неинвазивным вариантом было бы не использовать XmlDocument и не загружать поток более одного раза. Например, существующий код может быть упрощен/упрощен до:

foreach (string file in files) 
{ 
    using (var stream = new FileStream(file, FileMode.Open)) 
    { 
     var settings = new XmlReaderSettings(); 
     settings.CloseInput = false; 
     string version = ""; 
     using (var xmlReader = XmlReader.Create(stream)) 
     { 
      if (xmlReader.ReadToFollowing("Cars")) 
      { 
       version = xmlReader.GetAttribute("version"); 
      } 
      else 
      { 
       throw new XmlException("Could not get 'version' attribute of 'Cars' root element!"); 
      }      
     } 
     stream.Position = 0; 
     if (version == "1.00") 
     { 
      XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars)); 

      v1.Cars XML = new v1.Cars(); 
      XML = (v1.Cars)serializer.Deserialize(stream); 
     } 
     else if (version == "2.00") 
     { 
      XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars)); 

      v2.Cars XML = new v2.Cars(); 
      XML = (v2.Cars)serializer.Deserialize(stream); 

     } 
    } 
} 

Поскольку вы просто прочитывать корневой элемент, вы могли бы даже быть в состоянии уйти с десериализацией из XmlReader и не должно сбросить позицию на FileStream.

Это позволяет избежать накладных расходов на загрузку всего файла дважды (один раз за XmlDocument, а затем за XmlSerializer) - и, в частности, позволяет избежать накладных расходов памяти на создание DOM для каждого документа.

Более ядерный вариант будет реализовывать IXmlSerializable в наборе пользовательских классов, который будет иметь пользовательскую логику в методах ReadXml для анализа атрибута версии и создания экземпляра правильного дочернего типа (ов) - например, a CarCollection класс, который имеет свойство List<Car>, где Car является абстрактным классом, который имеет CarV1 и CarV2 как потомки. Это будет примерно так же эффективно, как вы могли бы получить (и предлагать очень тонкий контроль над дизайном иерархии классов), но исключает возможность использования xsd.exe для генерации ваших классов.