将XML文件映射到C#类

3
我知道将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#类中?

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

是否有人知道我是否可以通过在我的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);
                }
            }

        }
    }

请展示一下您已经尝试了什么? - CodeNotFound
请展示您用于反序列化的类。 - CodeNotFound
3个回答

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?。它还不包括任何自动类生成 - 如果涉及大量属性或经常更改,则需要编写实用程序来执行此操作。


是的,它将调用“ReadXml”方法来实际执行反序列化工作。 - Dan Field
如果您有解决方案,应该将其发布为答案。如果您想接受它作为答案,那很好,尽管如果这个答案有帮助并且让您到达了目的地,您也可以接受这个答案(或至少投票支持它)。就验证而言,我会编写一个单元测试方法,其中包含一个嵌入式XML示例,您知道它应该使用有效值填充每个属性,并迭代类型的.GetProperties()以确保每个属性都已设置。 - Dan Field
谢谢!我已经为你点赞了,但是我的声望还不够计入。 - Jesper Christensen
这取决于您使用哪个类来访问XML或它是否在您创建的对象中。如果您想在ReadXml方法中执行此操作,那么只需检查propName ==“Price”即可。 - Dan Field
我已经在这里发布了问题:http://stackoverflow.com/questions/35514071/how-to-find-xmlnodes-based-on-a-child-elements-name-and-value 非常感谢您的帮助! - Jesper Christensen
显示剩余5条评论

0

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);
                }
            }

        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接