1

I am working on XML data serialization and I have a Invoice XML. First of all I have Body class which has Item node. So I want to serizalize it with multiple Item node.

Let me show you what I tried, here is my Body and Item Class:

[XmlRoot("Body")]
public class Body
{
    [XmlElement("Invoice")]
    public int Invoice { get; set; }

    [XmlElement("Table")]
    public int Table { get; set; }

    [XmlElement("Outlet")]
    public int Outlet { get; set; }

    [XmlElement("User")]
    public int User { get; set; }

    [XmlElement("Creation")]
    public int Creation { get; set; }

    [XmlElement("Item")]
    public Item item { get; set; }
}

[XmlRoot("Item")]
public class Item
{
    [XmlElement("Type")]
    public string? Type { get; set; }

    [XmlElement("Productgroup")]
    public int? Productgroup { get; set; }

    [XmlElement("TotalAmount")]
    public double? TotalAmount { get; set; }

    [XmlElement("TaxClassification")]
    public double? TaxClassification { get; set; }

    [XmlElement("Text")]
    public string? Text { get; set; }

    [XmlElement("ResNo")]
    public int? ResNo { get; set; }
}

In here I created a class using Body and Items properties. My mainly aim is to get full rows but when I don't input some values it looks as 0. But I don't want to see empty rows. Other hand, I want to list mutiple Item Nodes of Body in my XML file. Let me show you my XML outputs and main.cs

Here is my XML output:

<?xml version="1.0" encoding="utf-8"?>
<Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Invoice>4711</Invoice>
  <Table>8</Table>
  <Outlet>3</Outlet>
  <User>17</User>
  <Creation>20140101</Creation>
  <Item>
    <Type>Revenue</Type>
    <Productgroup>5</Productgroup>
    <TotalAmount xsi:nil="true" />
    <TaxClassification xsi:nil="true" />
    <ResNo xsi:nil="true" />
 </Item>
</Body>

And here is my main program:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Body body = new Body 
            { 
                Invoice = 4711, 
                Table = 8 / 1, 
                Outlet = 3, 
                User = 17, 
                Creation = 20140101, 
                item = new Item {
                    Type="Revenue", 
                    Productgroup=5
                }
            };
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Body));
            StreamWriter sw = new StreamWriter("CloseInvoice.xml");
            xmlSerializer.Serialize(sw, body);
            sw.Close();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

But when I want to add new Item row with properties. I can not do it. What can I try next?

halfer
  • 19,824
  • 17
  • 99
  • 186
  • 1
    From what I understand you just need to change `Item item` to `Item[] items` or `List items` and populate this with your data. – mrogal.ski Jan 20 '21 at 18:55
  • Thank you for response but actually I did not understand exactly, can you please expand it? – Cugureleuro Jan 20 '21 at 19:00

2 Answers2

2

Expanding on my comment. What you're looking for is basically a type of collection/list/table which can store many items of the same type.

There are many different collection types so let's focus on the one mostly used in cases similar to yours which are List<> and Array.


On the example of your class, if you want to have more than one Item you should change that property from Item to List<Item> or Item[]

[XmlRoot("Body")]
public class Body
{
    [XmlElement("Invoice")]
    public int Invoice { get; set; }

    [XmlElement("Table")]
    public int Table { get; set; }

    [XmlElement("Outlet")]
    public int Outlet { get; set; }

    [XmlElement("User")]
    public int User { get; set; }

    [XmlElement("Creation")]
    public int Creation { get; set; }

    [XmlArray("Items")]                 // <-- here I changed the name for convenience
    public List<Item> Items { get; set; } // <-- here we change Item to List<Item>
}

To get do not serialize properties that doesn't have value you should create method for for each property called ShouldSerialize like such:

[XmlRoot("Item")]
public class Item
{
    // other properties

    [XmlElement("Productgroup")]
    public int? Productgroup { get; set; }
    public bool ShouldSerializeProductgroup() 
    {
        return Productgroup.HasValue;
    }

    [XmlElement("TotalAmount")]
    public double? TotalAmount { get; set; }
    public void ShouldSerializeTotalAmount()
    {
        return TotalAmount.HasValue;
    }

    // other properties
}

Now all you have to do with you serialization is to instantiate the List<Item> and populate it with the Items you need.

Body body = new Body 
{ 
    Invoice = 4711, 
    Table = 8 / 1, 
    Outlet = 3, 
    User = 17, 
    Creation = 20140101, 
    Items = new List<Item> 
    {
        new Item 
        {
            Type = "Revenue", 
            Productgroup = 5
        },
        new Item
        {
            Type = "AnotherType",
            Productgroup = 10
        }
    }
};

Test this online: https://rextester.com/SNZA69439

mrogal.ski
  • 5,828
  • 1
  • 21
  • 30
0

you can use this code:

XDocument xDocument = XDocument.Load("CloseInvoice.xml");
XElement root= xDocument.Element("Body");
//add new record...
xDocument.Save("CloseInvoice.xml");

Appending an existing XML file with XmlWriter

Meysam Asadi
  • 6,438
  • 3
  • 7
  • 17