将 XML 文件映射到 C# class

Mapping XML file to a C# class

我知道将 xml 反序列化为 C# classes 是很常见的事情,我以前也做过。但是我收到了一个 XML 格式的文件,我很难正确反序列化。当我从 XML 生成 C# class 时。我得到一种我不想要的格式。基本上所有属性都获得列类型..

基本的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]]>

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

我试过添加 ElementNameAttributeName 但没有成功。我可以使用 XmlSerializer 将其直接映射到 C# class 吗?

它完美地映射了自动生成的 class 但它以列和 columnName 的列表结束..

有谁知道我是否可以在我的 c# class 上使用一些 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);
                }
            }

        }
    }

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

您可能会考虑使用 XSLT 将 XML 转换为 XmlSerializer 可以阅读的内容,但如果仅此而已,我认为在这种情况下您需要实施 IXmlSerializable 自定义 class。这是我拼凑的东西,使用反射将 columnName 解析为 Order class.

中的 属性

如果您需要序列化回这种格式,这应该是相当简单的。

[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? 即可。它还不包括任何类型的自动生成 class - 如果有很多属性在起作用或它们经常更改,我会编写一个实用程序来执行此操作。

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

        }
    }