valen
valen

Reputation: 3

C# How to Group List for XML Object

I need help, for group by my XML object class.

Here my data from SQL server, my Query ( select * from TaxXMLdb ) =

TIN DocEntryAR BuyerDocNum BuyerName Opt ItemCode Name DocEntryAR2
AAA 100100 5533 Anto 0 2001 Book 100100
AAA 100100 5533 Anto 0 2002 Desk 100100
AAA 100100 5533 Anto 0 2003 Key 100100
AAA 200100 7722 Dani 0 5001 Lamp 200100
AAA 200100 7722 Dani 0 5002 Car 200100
AAA 300100 2211 Nina 0 3001 Fan 300100

I want XML output look like this,

Group By DocEntryAR Header, for each Detail (Opt, ItemCode, Name, DocEntryAR2)

((DocEntryAR, BuyerDocNum, BuyerName) as Header)

((Opt, ItemCode, Name, DocEntryAR2) as Detail), XML output must look like this below:

<TaxInvoiceBulk>
    <TIN>AAA</TIN>
    <ListOfTaxInvoice>
        <TaxInvoice>
            <DocEntryAR>100100</DocEntryAR>
            <BuyerDocNum>5533</BuyerDocNum>
            <BuyerName>Anto</BuyerName>
            <ListOfGoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2001</ItemCode>
                    <Name>Book</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2002</ItemCode>
                    <Name>Desk</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2003</ItemCode>
                    <Name>Key</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
            </ListOfGoodService>
        </TaxInvoice>
        <TaxInvoice>
            <DocEntryAR>200100</DocEntryAR>
            <BuyerDocNum>7722</BuyerDocNum>
            <BuyerName>Dani</BuyerName>
            <ListOfGoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>5001</ItemCode>
                    <Name>Lamp</Name>
                    <DocEntryAR2>200100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>5002</ItemCode>
                    <Name>Car</Name>
                    <DocEntryAR2>200100</DocEntryAR2>
                </GoodService>
            </ListOfGoodService>
        </TaxInvoice>
        <TaxInvoice>
            <DocEntryAR>300100</DocEntryAR>
            <BuyerDocNum>2211</BuyerDocNum>
            <BuyerName>Nina</BuyerName>
            <ListOfGoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>3001</ItemCode>
                    <Name>Fan</Name>
                    <DocEntryAR2>300100</DocEntryAR2>
                </GoodService>
            </ListOfGoodService>
        </TaxInvoice>
    </ListOfTaxInvoice>
</TaxInvoiceBulk>

I use that XML class List & code can Generate XML from C#

using System.Xml.Serialization;

but my output XML still Wrong result, not look like I want.

Anyone can help for Repair / Creating new List Class & Group by us LinQ, or other else solution for output XML like that. my class =

    [Serializable]
    [XmlType(TypeName = "TaxInvoiceBulk")]
    public class TaxInvoiceBulk
    {
        public string TIN { get; set; }
        [XmlArray("ListOfTaxInvoice")] // <--
        public List<TaxInvoice> TaxInvoices { get; set; }
        public TaxInvoiceBulk()
        {
            TaxInvoices = new List<TaxInvoice>();
        }

        [Serializable]
        public class TaxInvoice
        {
            public string DocEntryAR { get; set; }
            public string BuyerDocNum { get; set; }
            public string BuyerName { get; set; }
            [XmlArray("ListOfGoodService")] // <--
            public List<GoodService> GoodServices { get; set; }
            public TaxInvoice()
            {
                GoodServices = new List<GoodService>();
            }
        }

        [Serializable]
        public class GoodService
        {
            public string Opt { get; set; }
            public string ItemCode { get; set; }
            public string Name { get; set; }
            public string DocEntryAR2 { get; set; }
        }
    }

My Full Code in C# using System.Xml.Serialization;

  1. Declare XML class as public
public TaxInvoiceBulk Tax123 = new TaxInvoiceBulk();

than 2. Show in DataGrid First

private void btnGrid_Click(object sender, EventArgs e)
{
    SqlConnection myConnection = KonekSQL.create_concection();
    SqlDataAdapter dataAdapter = null;
    DataTable dataTable = null;

    //////string sql = $@"SELECT * FROM TaxXMLdb";
    string sql = $@"SELECT  DISTINCT(DocEntryAR), TIN, BuyerDocNum, BuyerName FROM TaxXMLdb";

    dataAdapter = new SqlDataAdapter(sql, myConnection);
    dataTable = new DataTable();
    dataAdapter.Fill(dataTable);
    dataGridView1.DataSource = dataTable;

    dataGridView1.AllowUserToAddRows = false; ////datagridview remove empty row.
    myConnection.Close();

    fillToXmlClass();
}
  1. make function to fill TaxInvoiceBulk Tax123 (fillToXmlClass()) from grid & 1 more SQL
public void fillToXmlClass()
    {
        string doken1 = null;

        SqlConnection myConnection = KonekSQL.create_concection();
        SqlDataReader myReader = null;
        SqlCommand myCommand = null;


        for (int i = 0; i < dataGridView1.Rows.Count; i += 1)
        {

            doken1 = dataGridView1.Rows[i].Cells["DocEntryAR"].Value.ToString();

            Tax123.TaxInvoices.Add(new TaxInvoice
            {
                DocEntryAR = dataGridView1.Rows[i].Cells["DocEntryAR"].Value.ToString(),
                BuyerDocNum = dataGridView1.Rows[i].Cells["BuyerDocNum"].Value.ToString(),
                BuyerName = dataGridView1.Rows[i].Cells["BuyerName"].Value.ToString()

            });

            string sql = $@"SELECT * FROM TaxXMLdb WHERE DocEntryAR = '{doken1}'";
            myCommand = new SqlCommand(sql, myConnection);
            myReader = myCommand.ExecuteReader();


            while (myReader.Read())
            {
                Tax123.TaxInvoices.FirstOrDefault().GoodServices.Add(new GoodService
                {
                    DocEntryAR2 = myReader["DocEntryAR2"].ToString(),
                    Opt = myReader["Opt"].ToString(),
                    ItemCode = myReader["ItemCode"].ToString(),
                    Name = myReader["Name"].ToString()
                });


            }//END While

        }//END Loop FOR GRID
        myConnection.Close();
}

then 4. I show it XML result using Message box

private void btnXML_Click(object sender, EventArgs e)
{
    var serialXML1 = new XmlSerializer(typeof(TaxInvoiceBulk));
    using (StringWriter textWriter1 = new StringWriter())
    {
        serialXML1.Serialize(textWriter1, Tax123);
        MessageBox.Show($@"{textWriter1.ToString()}");
    }
}
  1. My result XML still wrong, I don't know how to Group GoodService, by TaxInvoice.DocEntryAR.
<?xml version="1.0"?>
<TaxInvoiceBulk
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ListOfTaxInvoice>
        <TaxInvoice>
            <DocEntryAR>100100</DocEntryAR>
            <BuyerDocNum>5533</BuyerDocNum>
            <BuyerName>Anto</BuyerName>
            <ListOfGoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2001</ItemCode>
                    <Name>Book</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2002</ItemCode>
                    <Name>Desk</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>2003</ItemCode>
                    <Name>Key</Name>
                    <DocEntryAR2>100100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>5001</ItemCode>
                    <Name>Lamp</Name>
                    <DocEntryAR2>200100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>5002</ItemCode>
                    <Name>Car</Name>
                    <DocEntryAR2>200100</DocEntryAR2>
                </GoodService>
                <GoodService>
                    <Opt>0</Opt>
                    <ItemCode>3001</ItemCode>
                    <Name>Fan</Name>
                    <DocEntryAR2>300100</DocEntryAR2>
                </GoodService>
            </ListOfGoodService>
        </TaxInvoice>
        <TaxInvoice>
            <DocEntryAR>200100</DocEntryAR>
            <BuyerDocNum>7722</BuyerDocNum>
            <BuyerName>Dani</BuyerName>
            <ListOfGoodService />
        </TaxInvoice>
        <TaxInvoice>
            <DocEntryAR>300100</DocEntryAR>
            <BuyerDocNum>2211</BuyerDocNum>
            <BuyerName>Nina</BuyerName>
            <ListOfGoodService />
        </TaxInvoice>
    </ListOfTaxInvoice>
</TaxInvoiceBulk>

Upvotes: 0

Views: 75

Answers (1)

Yitzhak Khabinsky
Yitzhak Khabinsky

Reputation: 22293

Here is a solution based on SQL Server T-SQL that is composing desired output XML in one single statement.

XML hierarchy has three levels: parent, child, and grandchild. It is visible through nested SELECT ... FOR XML ... statements with corresponding aliases.

And just call it directly from the c# program, or package it as an SQL Server stored procedure.

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (
    TIN CHAR(3), 
    DocEntryAR CHAR(6), 
    BuyerDocNum INT, 
    BuyerName VARCHAR(20),
    Opt BIT,
    ItemCode CHAR(4),
    Name VARCHAR(30),
    DocEntryAR2 CHAR(6));
INSERT INTO @tbl VALUES
('AAA', '100100', 5533, 'Anto', 0, 2001, 'Book', 100100),
('AAA', '100100', 5533, 'Anto', 0, 2002, 'Desk', 100100),
('AAA', '100100', 5533, 'Anto', 0, 2003, 'Key',  100100),
('AAA', '200100', 7722, 'Dani', 0, 5001, 'Lamp', 200100),
('AAA', '200100', 7722, 'Dani', 0, 5002, 'Car',  200100),
('AAA', '300100', 2211, 'Nina', 0, 3001, 'Fan',  300100);
-- DDL and sample data population, end

SELECT TIN
    , (
        SELECT DocEntryAR, BuyerDocNum, BuyerName
    , (
        SELECT Opt, ItemCode, Name, DocEntryAR2
        FROM @tbl AS gc -- grandchild
        WHERE c.DocEntryAR = gc.DocEntryAR
            AND c.BuyerDocNum = gc.BuyerDocNum
            AND c.BuyerName = gc.BuyerName
        FOR XML PATH('GoodService'), TYPE, ROOT('ListOfGoodService')
    )
    FROM @tbl AS c  -- child
    WHERE p.TIN = c.TIN
    GROUP BY DocEntryAR, BuyerDocNum, BuyerName
    FOR XML PATH('TaxInvoice'), TYPE, ROOT('ListOfTaxInvoice')
)
FROM @tbl AS p -- parent
GROUP BY TIN
FOR XML PATH(''), TYPE, ROOT('TaxInvoiceBulk');

Output

<TaxInvoiceBulk>
  <TIN>AAA</TIN>
  <ListOfTaxInvoice>
    <TaxInvoice>
      <DocEntryAR>100100</DocEntryAR>
      <BuyerDocNum>5533</BuyerDocNum>
      <BuyerName>Anto</BuyerName>
      <ListOfGoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>2001</ItemCode>
          <Name>Book</Name>
          <DocEntryAR2>100100</DocEntryAR2>
        </GoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>2002</ItemCode>
          <Name>Desk</Name>
          <DocEntryAR2>100100</DocEntryAR2>
        </GoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>2003</ItemCode>
          <Name>Key</Name>
          <DocEntryAR2>100100</DocEntryAR2>
        </GoodService>
      </ListOfGoodService>
    </TaxInvoice>
    <TaxInvoice>
      <DocEntryAR>200100</DocEntryAR>
      <BuyerDocNum>7722</BuyerDocNum>
      <BuyerName>Dani</BuyerName>
      <ListOfGoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>5001</ItemCode>
          <Name>Lamp</Name>
          <DocEntryAR2>200100</DocEntryAR2>
        </GoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>5002</ItemCode>
          <Name>Car</Name>
          <DocEntryAR2>200100</DocEntryAR2>
        </GoodService>
      </ListOfGoodService>
    </TaxInvoice>
    <TaxInvoice>
      <DocEntryAR>300100</DocEntryAR>
      <BuyerDocNum>2211</BuyerDocNum>
      <BuyerName>Nina</BuyerName>
      <ListOfGoodService>
        <GoodService>
          <Opt>0</Opt>
          <ItemCode>3001</ItemCode>
          <Name>Fan</Name>
          <DocEntryAR2>300100</DocEntryAR2>
        </GoodService>
      </ListOfGoodService>
    </TaxInvoice>
  </ListOfTaxInvoice>
</TaxInvoiceBulk>

Upvotes: 0

Related Questions