2016-02-18 4 views
3

Я знаю, что десериализация классов xml на C# является обычной практикой, и я делал это раньше. Но ive получил XML-файл с форматом im, который имеет жесткое десериализацию. Когда я генерирую класс C# из XML. Я получаю формат, который я не хочу. В основном все свойства получают тип столбца.Сопоставление XML-файла с классом C#

Основной формат XML выглядит следующим образом. Дело в том, что у меня 250 свойств, и я действительно не хочу вручную сопоставлять каждую.

<item table="Order"> 
    <column columnName="Id"><![CDATA[2]]></column> 
    <column columnName="Price"><![CDATA[200]]></column> 
    <column columnName="Date"><![CDATA[25-01-2036 13:29:24:310]]> 

Я на самом деле вручную написал класс, который имеет правильные свойства. Id, price, date и так далее ...

Я попытался с добавлением ElementName и AttributeName не повезло. Возможно ли мне сопоставить это непосредственно с классом C#, используя XmlSerializer?

Он прекрасно отображает сгенерированный класс, но он заканчивает со списком colums и ColumnName ..

ли кто-нибудь знает, если я могу возможно исправить это с некоторой XML нотацией на моем C# класса, чтобы получить его слишком карту правильно ?

-------------- Solution --------------

Благодаря @Dan поле для получения меня на верном пути!

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

public void ReadXml(XmlReader reader) 
    { 
     while (reader.Read()) 
     { 
      if (reader.NodeType == XmlNodeType.Element && reader.Name == "column") 
      { 
       PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(EcomOrder)); 
       string propName = reader.GetAttribute("columnName"); 

       // Retrieve the property Descriptor 
       PropertyDescriptor prop = props[propName]; 

       if (prop != null) 
       { 
        reader.Read(); // move to CDATA (or text) node 

        // use DateTime.ParseExact instead for DateTime field 
        if (prop.PropertyType == typeof(DateTime?) || prop.PropertyType == typeof(DateTime)) 
        { 
         prop.SetValue(this, 
          DateTime.ParseExact(reader.Value, "dd-MM-yyyy HH:mm:ss:fff", CultureInfo.InvariantCulture)); 
        } 
        else 
        { 
         prop.SetValue(this, 
          prop.Converter.ConvertFromInvariantString(reader.Value)); 
        } 
       } 
       else 
       { 
        throw new XmlException("Property not found: " + propName); 
       } 
      } 

     } 
    } 
+0

Покажите нам, что вы уже пробовали? – CodeNotFound

+0

Покажите нам класс, который вы используете для десериализации. – CodeNotFound

ответ

0

Благодаря @Dan Field, чтобы получить меня на правильном пути!

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

public void ReadXml(XmlReader reader) 
    { 
     while (reader.Read()) 
     { 
      if (reader.NodeType == XmlNodeType.Element && reader.Name == "column") 
      { 
       PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(EcomOrder)); 
       string propName = reader.GetAttribute("columnName"); 

       // Retrieve the property Descriptor 
       PropertyDescriptor prop = props[propName]; 

       if (prop != null) 
       { 
        reader.Read(); // move to CDATA (or text) node 

        // use DateTime.ParseExact instead for DateTime field 
        if (prop.PropertyType == typeof(DateTime?) || prop.PropertyType == typeof(DateTime)) 
        { 
         prop.SetValue(this, 
          DateTime.ParseExact(reader.Value, "dd-MM-yyyy HH:mm:ss:fff", CultureInfo.InvariantCulture)); 
        } 
        else 
        { 
         prop.SetValue(this, 
          prop.Converter.ConvertFromInvariantString(reader.Value)); 
        } 
       } 
       else 
       { 
        throw new XmlException("Property not found: " + propName); 
       } 
      } 

     } 
    } 
1

Вы можете рассмотреть возможность использования XSLT для преобразования XML к чему-то XmlSerializer может читать, но если это только это, я думаю, что это тот случай, где вы хотите реализовать IXmlSerializable в пользовательском классе. Вот что я взбивал вместе, используя отражение, чтобы разобрать columnName в собственность класса Order.

Если вам нужно сериализовать обратно в этот формат, это должно быть довольно тривиально.

[XmlRoot("item")] 
public class Order : IXmlSerializable 
{ 

    public int Id { get; set; } 
    public int Price { get; set; } 
    public DateTime Date { get; set; } 

    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     while (reader.Read()) 
     { 
      if (reader.NodeType == XmlNodeType.Element && reader.Name == "column") 
      { 
       string propName = reader.GetAttribute("columnName"); // get the property info... 
       PropertyInfo prop = typeof(Order).GetProperty(propName, 
         BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty); 
       if (prop != null && prop.CanWrite) 
       { 
        reader.Read(); // move to CDATA (or text) node 
        // can use Convert.ChangeType for most types 
        // use DateTime.ParseExact instead for DateTime field 
        if (prop.PropertyType != typeof(DateTime)) 
        { 
         prop.SetValue(this, 
          Convert.ChangeType(reader.Value, prop.PropertyType, CultureInfo.InvariantCulture)); 
        } 
        else 
        { 
         prop.SetValue(this, 
          DateTime.ParseExact(reader.Value, "dd-MM-yyyy HH:mm:ss:fff", CultureInfo.CurrentCulture)); 
        } 
       } 
       else 
       { 
        throw new XmlException("Property not found: " + propName); 
       } 
      }      

     } 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Вы, вероятно, придется сделать немного больше работы, если есть какие-либо другие типы в то, что нужны специальные соображения синтаксического анализа. Это вызовет исключение, если вы получите пустое значение для узла int, хотя - может работать только с использованием int?, если это так. Он также не включает в себя какой-либо генерации автоматического класса - я бы написал утилиту, чтобы сделать это, если в игре было много свойств или они часто менялись.

+0

Я обязательно попробую это, когда я получу время! Я напишу еще раз, когда надеюсь, что это сработает! ;) Если я правильно понимаю, я могу просто назвать свой десериализатор, как обычно, и он будет использовать этот readXml вместо стандартного? –

+0

Для реального использования определенно потребуется немного больше - некоторые типы не будут эффективно конвертироваться только с помощью 'Convert.ChangeType', и он не будет иметь дело с нулями, если у вас есть поля с нулевым значением, как есть. –

+0

И да, это вызовет метод ReadXml, чтобы фактически выполнить работу по десериализации. –

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