Home > Enterprise >  convert xml nested items to c# model
convert xml nested items to c# model

Time:04-09

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,
        });
  • Related