我知道将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); } } } }I know that deserializing xml to C# classes is a common thing and I've done it before. But ive received an XML file with a format im having a hard time deserializing properly. When i generate a C# class from the XML. I get a format I dont want. Basically all the properties get the column type..
The basic XML format is like below. The thing is that I have 250 properties and I really don't want to manually map every single one.
<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]]>I've actually manually written a class that has the correct properties. Id, price, date and so on...
I've tried with adding ElementName and AttributeName with no luck. Is it possible for me to map this directly to a C# class using XmlSerializer?
It perfectly maps the autogenerated class but it ends up with a list of colums and columnName..
Do anyone know if I can possible fix this with some xml notations on my c# class to get it too map properly?
-------------- Solution --------------
Thanks to @Dan Field for getting me on the right track!
as he points out himself there was a problem with nullable attributes in his solution. So i hunted another one down and this is what i came up with!
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); } } } }最满意答案
您可以考虑使用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? 如果是这样的话。 它也不包括任何类型的自动类生成 - 如果有很多属性在运行或经常更改,我会编写一个实用程序来执行此操作。
Thanks to @Dan Field for getting me on the right track!
as he points out himself there was a problem with nullable attributes in his solution. So i hunted another one down and this is what i came up with!
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#类(Mapping XML file to a C# class)我知道将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); } } } }I know that deserializing xml to C# classes is a common thing and I've done it before. But ive received an XML file with a format im having a hard time deserializing properly. When i generate a C# class from the XML. I get a format I dont want. Basically all the properties get the column type..
The basic XML format is like below. The thing is that I have 250 properties and I really don't want to manually map every single one.
<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]]>I've actually manually written a class that has the correct properties. Id, price, date and so on...
I've tried with adding ElementName and AttributeName with no luck. Is it possible for me to map this directly to a C# class using XmlSerializer?
It perfectly maps the autogenerated class but it ends up with a list of colums and columnName..
Do anyone know if I can possible fix this with some xml notations on my c# class to get it too map properly?
-------------- Solution --------------
Thanks to @Dan Field for getting me on the right track!
as he points out himself there was a problem with nullable attributes in his solution. So i hunted another one down and this is what i came up with!
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); } } } }最满意答案
您可以考虑使用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? 如果是这样的话。 它也不包括任何类型的自动类生成 - 如果有很多属性在运行或经常更改,我会编写一个实用程序来执行此操作。
Thanks to @Dan Field for getting me on the right track!
as he points out himself there was a problem with nullable attributes in his solution. So i hunted another one down and this is what i came up with!
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); } } } }
发布评论