views:

34

answers:

1

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.

+3  A: 

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.

Fyodor Soikin
The nested foreach worked (don't know why I didn't see that). Also, thanks for the LINQ-to-XML query refinement, it's elegant.
billmaya