How can I iterate over a collection of objects returned by a LINQ-to-XML query?

I've got this XML:

<BillingLog>
  <BillingItem>
    <date-and-time>2003-11-04</date-and-time>
    <application-name>Billing Service</application-name>
    <severity>Warning</severity>
    <process-id>123</process-id>
    <description>Timed out on a connection</description>
    <detail>Timed out after three retries.</detail>
  </BillingItem>
  <BillingItem>
    <date-and-time>2010-05-15</date-and-time>
    <application-name>Callback Service</application-name>
    <severity>Error</severity>
    <process-id>456</process-id>
    <description>Unable to process callback</description>
    <detail>Reconciliation timed out after two retries.</detail>
  </BillingItem>
</BillingLog>

That I want to project using LINQ-to-XML into a collection of BillingItem objects contained in a single BillingLog object.

public class BillingLog
{
    public IEnumerable<BillingItem> items { get; set; }
}

public class BillingItem
{
    public string Date { get; set; }
    public string ApplicationName { get; set; }
    public string Severity { get; set; }
    public int ProcessId { get; set; }
    public string Description { get; set; }
    public string Detail { get; set;}       
}

This is the LINQ query that I'm using to project the XML (which is contained in the string variable source).

XDocument xdoc = XDocument.Parse(source);

var log = 
    from i in xdoc.Elements("BillingLog")
    select new BillingLog
    {
        items =
            from j in i.Descendants("BillingItem")
            select new BillingItem
            {
                Date = (string)j.Element("date-and-time"),
                ApplicationName = (string)j.Element("application-name"),
                Severity = (string)j.Element("severity"),
                ProcessId = (int)j.Element("process-id"),
                Description = (string)j.Element("description"),
                Detail = (string)j.Element("detail")
            }
    };

When I try and iterate over the objects in log using foreach.

foreach (BillingItem item in log)
{
Console.WriteLine ("{0} | {1} | {2} | {3} | {4} | {5}", 
                    item.Date, item.ApplicationName, 
                    item.Severity, item.ProcessId.ToString(), 
                    item.Description, item.Detail);
}   

I get the following error message from LINQPad.

Cannot convert type 'UserQuery.BillingLog' to 'UserQuery.BillingItem'

Thanks in advance.

Answers


That's because your log variable contains a collection of BillingLog objects, not BillingItem. You have to do something like:

foreach( BillingLog l in log )
{
    foreach( BillingItem item in l.items )
    {
        Console.WriteLine( ... );
    }
}

Alternatively, if your original intent was to just select all BillingItems, disregarding their parent BillingLogs completely, you could rewrite your query like so:

var log = 
        from l in xdoc.Elements("BillingLog")
        from j in l.Descendants("BillingItem")
        select new BillingItem
        {
            Date = (string)j.Element("date-and-time"),
            ApplicationName = (string)j.Element("application-name"),
            Severity = (string)j.Element("severity"),
            ProcessId = (int)j.Element("process-id"),
            Description = (string)j.Element("description"),
            Detail = (string)j.Element("detail")
        }

This will give you a plain collection of all BillingItemss selected from under all BillingLogs, while BillingLogs themselves will be completely discarded.


Need Your Help

SQL Compute the price of cart in one request

sql mysql django shopping-cart

Typically, I have a really simple cart with some items in it, with a quantity.

How to report invalid form fields using Backbone.js

backbone.js validation

I'm using Backbone to manage the state of an HTML form. The Model's role is to handle validation. The View's role is to wrap the HTML form and respond to the change or error events emitted by the m...