yash fale yash fale - 15 days ago 5
C# Question

how to get multiple records with same id if there is multiple <data> element in c# from xml

I want multiple records if there is a multiple data element , so id and log element will be remain same for each data record.

note : there will be multiple element in xml , below example , below is only for single

xml Code :

<pay>
<id>1</id>
<data>
<startDate>2016-03-03</startDate>
<adjustedDueDate>2016-03-31</adjustedDueDate>
<Rate>50</Rate>
</data>
<data>
<startDate>2016-04-04</startDate>
<adjustedDueDate>2016-04-04</adjustedDueDate>
<Rate>12</Rate>
</data>
<log>IMP</log>
</pay>


C# code

string path = @"E:\XMLFile1.xml";
XDocument xmlExeDoc = XDocument.Load(path);
var recordsFac = xmlExeDoc.Descendants("pay").Select(x => new
{
id = (string)x.Element("id"),
cycle = x.Elements("data").Select(y => new
{
startDate = (y.Elements("startDate").Any() == true) ? (string)y.Element("startDate") : string.Empty,
adjustedDueDate = (DateTime)y.Element("adjustedDueDate"),
Rate = (decimal)y.Element("Rate")
}).Where(y => y.Rate > 0 && y.adjustedDueDate < DateTime.Now)
.Select
(
c => new
{
startDate = c.startDate,
adjustedDueDate = c.adjustedDueDate,
Rate = c.Rate
}
).FirstOrDefault(),

log = x.Element("log")
}).ToList();


required output :

output:

[0] {1,2016-03-03,2016-03-31,50,IMP}



[1] {1,2016-04-04,2016-04-04,12,IMP}



need same output like here but another element added i have coded like given below is it right way to do it , need 2 rows of and 2 rows of element.



<pay>
<id>1</id>
<data>
<startDate>2016-03-03</startDate>
<adjustedDueDate>2016-03-31</adjustedDueDate>
<Rate>50</Rate>
</data>
<data>
<startDate>2016-04-04</startDate>
<adjustedDueDate>2016-04-04</adjustedDueDate>
<Rate>12</Rate>
</data>
<log>IMP</log>
</pay>
<ClientData>
<startDate>2016-07-04</startDate>
<adjustedDueDate>2016-08-04</adjustedDueDate>
<Rate>100</Rate>
</ClientData>
<ClientData>
<startDate>2016-09-04</startDate>
<adjustedDueDate>2016-09-04</adjustedDueDate>
<Rate>555</Rate>
</ClientData>
</pay>



var recordsFac = xmlExeDoc.Descendants("pay").Select(x => new
{

cycle = x.Elements("data").Select(y => new
{
id = (string)x.Element("id"),
startDate = (y.Elements("startDate").Any() == true) ? (string)y.Element("startDate") : string.Empty,
adjustedDueDate = (DateTime)y.Element("adjustedDueDate"),
Rate = (decimal)y.Element("Rate"),
log = x.Element("log")
}).Where(y => y.Rate > 0 && y.adjustedDueDate < DateTime.Now),
ClientData = x.Elements("data").Select(y => new
{
id = (string)x.Element("id"),
startDate = (y.Elements("startDate").Any() == true) ? (string)y.Element("startDate") : string.Empty,
adjustedDueDate = (DateTime)y.Element("adjustedDueDate"),
Rate = (decimal)y.Element("Rate"),
log = x.Element("log")
}).Where(y => y.Rate > 0 && y.adjustedDueDate < DateTime.Now)

}).ToList();


is the above code is right way to achieve this :

output :

[0] {1,2016-03-03,2016-03-31,50,IMP}



[1] {1,2016-04-04,2016-04-04,12,IMP}

[2] {1,2016-07-04,2016-08-04,100,IMP}



[3] {1,2016-09-04,2016-09-04,555,IMP}

Answer

Your queries are already producing what you're asking, but you're restricting the cycle query to FirstOrDefault, so it is only going to produce 1 record. If you remove that then cycle contains both records.

To get the id and log in the same record as the dates, just include them in the final anonymous class you're creating :

var recordsFac = xmlExeDoc.Descendants("pay").Select(x => new
{

    cycle = x.Elements("data").Select(y => new
    {
        startDate = (y.Elements("startDate").Any() == true) ? (string)y.Element("startDate") : string.Empty,
        adjustedDueDate = (DateTime)y.Element("adjustedDueDate"),
        Rate = (decimal)y.Element("Rate"),
    }).Where(y => y.Rate > 0 && y.adjustedDueDate < DateTime.Now)
                           .Select
                           (
                               c => new
                               {
                                   id = (string)x.Element("id"),
                                   startDate = c.startDate,
                                   adjustedDueDate = c.adjustedDueDate,
                                   Rate = c.Rate,
                                   log = x.Element("log")
                               }
                           ),

}).ToList();

recordsFac will contain records for each pay element in the xml file. the cycle property for each record will contain the data as you've outlined. A simple nested foreach loop will access the data:

foreach(var record in recordsFac)
{
    foreach(var record2 in record.cycle)
    {
        Console.WriteLine($"{record2.id},{record2.startDate},{record2.adjustedDueDate},{record2.log}");
    }
}

Just took another look at your code and noticed the last select is redundant and can be removed:

var recordsFac = xmlExeDoc.Descendants("pay").Select(x => new
{

    cycle = x.Elements("data").Select(y => new
    {
        id = (string)x.Element("id"),
        startDate = (y.Elements("startDate").Any() == true) ? (string)y.Element("startDate") : string.Empty,
        adjustedDueDate = (DateTime)y.Element("adjustedDueDate"),
        Rate = (decimal)y.Element("Rate"),
        log = x.Element("log")
    }).Where(y => y.Rate > 0 && y.adjustedDueDate < DateTime.Now)               
}).ToList();

foreach(var record in recordsFac)
{
    foreach(var record2 in record.cycle)
    {
        Console.WriteLine($"{record2.id},{record2.startDate},{record2.adjustedDueDate},{record2.log}");
    }
}
Comments