我知道将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]]>
我实际上是手动编写了一个具有正确属性的类。 Id
,price
,date
等等......
我尝试添加ElementName
和AttributeName
但没有运气。我可以使用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);
}
}
}
}
答案 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);
}
}
}
}