I have xml like this :
<Root>
<Products>
<Product>
<ProductCode>1</ProductCode>
<Properties no="45">
<ColorProperties>
<Color>Blue</Color>
</ColorProperties>
</Properties>
</Product>
<Product>
<ProductCode>2</ProductCode>
<Properties no="45">
<ColorProperties>
<Color>Red</Color>
</ColorProperties>
</Properties>
</Product>
<Product>
<ProductCode>3</ProductCode>
<Properties no="45">
<ColorProperties>
<Color>Yellow</Color>
</ColorProperties>
</Properties>
</Product>
</Products>
</Root>
And I want to convert to Product Model,
class Product
{
//must be filled
}
And there must me attributes for top of the Product class that say to Product belongs to Products and Products belong to Root.
How can I make this ?
My english not great sorry for that :) .
So I do not want create Root and Products Classes (there must be multiple [XmlRoot] I think), and I want decorate Properties (and it's nested properties) with [XmlArray] and [XmlArrayItem] but I could not make it.
How can convert this xml to Product class with c# ?
CodePudding user response:
You can try Cinchoo ETL - an open source library to deserialize selective nodes from xml in simplified way.
First define POCO class to with xpath to extract children from product node
public class Product
{
public int ProductCode { get; set; }
[ChoXPath("Properties/@no")]
public int PropertyNo { get; set; }
[ChoXPath("Properties/ColorProperties/Color")]
public string Color { get; set; }
}
Then use ChoXmlReader to load the product nodes from xml as below
using (var r = ChoXmlReader<Product>.LoadText(xml)
.WithXPath("//Product")
)
{
r.Print();
}
Output:
-- Program Product State --
ProductCode: 1
PropertyNo: 45
Color: Blue
-- Program Product State --
ProductCode: 2
PropertyNo: 45
Color: Red
-- Program Product State --
ProductCode: 3
PropertyNo: 45
Color: Yellow
Sample fiddle: https://dotnetfiddle.net/uBzXpt
CodePudding user response:
You can scaffold any entity to a POCO class by using Visual Studio's special paste magic ( Edit - Special Paste - Paste as XML )
And I exactly did that to generate your entity classes by using your XML file.
Now, Let's say we have the following Entity classes :
using System;
using System.ComponentModel;
using System.Xml.Serialization;
namespace XmlToClass
{
[Serializable()]
[DesignerCategory("code")]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public partial class Root
{
private RootProduct[] productsField;
[XmlArrayItem("Product", IsNullable = false)]
public RootProduct[] Products
{
get
{
return this.productsField;
}
set
{
this.productsField = value;
}
}
}
[Serializable()]
[DesignerCategory("code")]
[XmlType(AnonymousType = true)]
public partial class RootProduct
{
private byte productCodeField;
private RootProductProperties propertiesField;
public byte ProductCode
{
get
{
return this.productCodeField;
}
set
{
this.productCodeField = value;
}
}
public RootProductProperties Properties
{
get
{
return this.propertiesField;
}
set
{
this.propertiesField = value;
}
}
}
[Serializable()]
[DesignerCategory("code")]
[XmlType(AnonymousType = true)]
public partial class RootProductProperties
{
private RootProductPropertiesColorProperties colorPropertiesField;
private byte noField;
public RootProductPropertiesColorProperties ColorProperties
{
get
{
return this.colorPropertiesField;
}
set
{
this.colorPropertiesField = value;
}
}
[XmlAttribute()]
public byte no
{
get
{
return this.noField;
}
set
{
this.noField = value;
}
}
}
[Serializable()]
[DesignerCategory("code")]
[XmlType(AnonymousType = true)]
public partial class RootProductPropertiesColorProperties
{
private string colorField;
/// <remarks/>
public string Color
{
get
{
return this.colorField;
}
set
{
this.colorField = value;
}
}
}
}
Simply add this helper class with a generic method :
public class XmlToEntity
{
public T FromXml<T>(String xml)
{
T returnedXmlClass = default(T);
try
{
using (TextReader reader = new StringReader(xml))
{
try
{
returnedXmlClass =
(T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
catch (InvalidOperationException)
{
// String passed is not XML, simply return defaultXmlClass
}
}
}
catch (Exception ex)
{
}
return returnedXmlClass;
}
}
And try this in your console:
static void Main(string[] args)
{
var conv = new XmlToEntity();
Root root = conv.FromXml<Root>(File.ReadAllText("data.xml"));
Console.WriteLine(root.Products.Length.ToString());
}
Note:
If you wish to use different queries you can use anonymous types and a little LINQ as per below:
var query = root.Products.Select(x => new
{
ProductCode = x.ProductCode,
ProductColor = x.Properties.ColorProperties.Color,
});