LINQ to XML - How to get a dictionary from an anonymous object?

I am currently getting the HeaderColumns list from the following XML snippet:

<PerformancePanel>
  <HeaderColumns>
    <column performanceId="12" text="Over last month %" />
    <column performanceId="13" text="Over last 3 months %" />
    <column performanceId="16" text="1 Year %" />
    <column performanceId="18" text="3 Years % p.a." />
    <column performanceId="20" text="5 Years % p.a." />
    <column performanceId="22" text="10 Years % p.a." />
  </HeaderColumns>
</PerformancePanel>

      

from which I create an object like this: (validly similar to the earlier question!)

var performancePanels = new
{
    Panels = (from panel in doc.Elements("PerformancePanel")
            select new
            {
                HeaderColumns = (from column in panel.Elements("HeaderColumns").Elements("column")
                                 select new
                                 {
                                     PerformanceId = (int)column.Attribute("performanceId"),
                                     Text = (string)column.Attribute("text")
                                 }).ToList(),
              }).ToList()
};

      

I would like the HeaderColumns to be Dictionary (), so later I retrieve the values ​​from the anonymous object like:

Dictionary<int, string> myHeaders = new Dictionary<int, string>();
foreach (var column in performancePanels.Panels[0].HeaderColumns)
{
    myHeaders.Add(column.PerformanceId, column.Text);
}

      

I thought I could achieve this with Linq for XML with something similar to this

HeaderColumns = (from column in panel.Elements("HeaderColumns").Elements("column")
                 select new Dictionary<int, string>()
                 {
                     (int)column.Attribute("performanceId"),
                     (string)column.Attribute("text")
                 }).ToDictionary<int,string>(),

      

but it doesn't work because

  • ToDictionary () needs a Func parameter and I don't know what it is / how to implement it, and
  • the code is probably wrong anyway!

Can someone suggest me how I can achieve the result I want? Thank you.

Edit: I tried to implement the Spender solution below, but I'm having a hard time figuring out what I need to change in my code. Can anyone clarify? Thanks to

+2


a source to share


3 answers


I found this to be a suitable answer to this question:



How can I create a dictionary <int, string> via LINQ to XML?

0


a source


This is untested, but should do the trick:

panel
    .Elements("HeaderColumns")
    .Elements("column")
    .ToDictionary(
        column=>(int)column.Attribute("performanceId"),
        column=>(string)column.Attribute("text")
    )

      

In this case, I am using the following ToDictionary overload :

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    Func<TSource, TElement> elementSelector
)

      

So here it source

will be:

panel
    .Elements("HeaderColumns")
    .Elements("column")

      

Both keySelector

and elementSelector

are functions (delegates) that take an element of type TSource (from source

) and return the value obtained from the element:



keySelector

:

        column=>(int)column.Attribute("performanceId")

      

elementSelector

:

        column=>(string)column.Attribute("text")

      

They are declared in lambda format. The dictionary type is then inferred from the return types of the delegates. In this case it will be Dictionary<int,string>

.

The generic delegate Func<TSource, TKey>

will define the type of the method that takes a parameter of type TSource and returns a value of type TKey. It is very important to understand what this means in order to have a productive time using Linq extension methods.

+2


a source


It is difficult to give a complete answer as your xml and C # are not the same; but from each "HeaderColumns" you can use:

var columns = from column in headerColumns.Elements("column")
              select new {
                  PerformanceId = (int)column.Attribute("performanceId"),
                  Text = (string)column.Attribute("text")
              };
Dictionary<int, string> myHeaders = columns.ToDictionary(
    column => column.PerformanceId, column => column.Text);

      

If you have several <HeaderColumns>

, then SelectMany

maybe ...

var columns = from panel in doc.Elements("PerformancePanel")
              from headers in panel.Elements("HeaderColumns")
              from column in headers.Elements("column")
              select new {
                  PerformanceId = (int)column.Attribute("performanceId"),
                  Text = (string)column.Attribute("text")
              };
Dictionary<int, string> myHeaders = columns.ToDictionary(
    column => column.PerformanceId, column => column.Text);

      

+1


a source







All Articles