2016-02-18 67 views
3

我知道將xml反序列化爲C#類是很常見的事情,我之前就已經完成了。但是,ive收到了一個格式爲im的XML文件,該格式很難正確反序列化。當我從XML生成一個C#類。我得到了我不想要的格式。基本上所有的屬性獲得列類型。將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]]> 

我實際上已經手動編寫了一個具有正確屬性的類。 Idpricedate等等...

我試着加入ElementNameAttributeName沒有運氣。我可以使用XmlSerializer直接將它映射到C#類嗎?

它完美地映射自動生成的類,但它與colums和列名的列表,結束了..

不要任何人都知道,如果我能有可能修復這個對我的C#類中的一些XML的符號來得到它太映射正確?

-------------- --------------解決

感謝@丹現場爲我安排在正確的軌道上!

他指出自己在解決方案中存在可空屬性的問題。所以我找到了另一個,這就是我想出來的!

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可以閱讀recomendtions,但如果只是這樣,我認爲這是一個情況下,你需要在自定義類上實現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來轉換properties,並且如果您有空的字段,它將不會處理空值。 –

+0

是的,它會調用'ReadXml'方法來實際執行反序列化工作。 –