将XML文件映射到C#类

时间:2016-02-18 21:05:50

标签: c# xml xml-parsing xmlserializer

我知道将xml反序列化为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]]>

我实际上是手动编写了一个具有正确属性的类。 Idpricedate等等......

我尝试添加ElementNameAttributeName但没有运气。我可以使用XmlSerializer直接将它映射到C#类吗?

它完美地映射了自动生成的类,但最终得到了colums列和columnName ..

有人知道我是否可以使用我的c#类中的一些xml符号修复此问题,以使其得到正确映射?

--------------解决方案--------------

感谢@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);
                }
            }

        }
    }

3 个答案:

答案 0 :(得分: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?。它也不包括任何类型的自动类生成 - 如果有很多属性在运行或者它们经常更改,我会编写一个实用程序。

答案 1 :(得分:0)

我认为不可能直接映射。 您可以使用XPathNavigator进行映射,也可以按照Marc Gravell in the following post 的建议进行操作 Deserialize xml base on attribute name as properties of my class in C#

答案 2 :(得分: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);
                }
            }

        }
    }