将 XML 文件映射到 C# 类

本文关键字:映射 XML 文件 | 更新日期: 2023-09-27 18:35:26

我知道将xml反序列化为C#类是一件很常见的事情,我以前也做过。但是我收到了一个格式为 im 的 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# 类?

它完美地映射了自动生成的类,但它最终得到了一个列和列名的列表。

有谁知道我是否可以在我的 c# 类上使用一些 xml 表示法来解决这个问题,以使其也正确映射?

--------------溶液--------------

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

将 XML 文件映射到 C# 类

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

我认为不可能直接映射。您可以使用XPathNavigator进行映射,也可以遵循Marc Gravell在以下文章中的建议。在 C# 中将基于属性名称的 xml 反序列化为我的类的属性

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