intelliWork
intelliWork

Reputation: 185

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable>>' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists

I am using below query to return all the child elements and then based on child node i want to fetch the result.

XElement rootElement = XElement.Load(@"E:\Samples\TestConsole\TestConsoleApp\TestConsoleApp\XMLFile1.xml");
        IEnumerable<XElement> lv1s = from lv1 in rootElement.Descendants("A")
                   where lv1.Attribute("Code").Value.Equals("A001") && lv1.Attribute("Lable").Value.Equals("A001")
                   select (from ltd in lv1.Descendants("A1")
                           where ltd.Attribute("Code").Value.Equals("001")
                           select ltd.Elements()).ToList();

But still i am having following error.

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Collections.Generic.List<System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>>>' to 'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>'. An explicit conversion exists (are you missing a cast?)

Please let me know.

i want my value of lv1s["A11"], lv1s["A22"]

below is my xml

    <?xml version="1.0" encoding="utf-8" ?>
<Document>
  <A Code="A001" Lable="A001">
    <A1 Code="001">
      <A11>A1</A11>
      <A22>A2</A22>
      <A33>A3</A33>
    </A1>
  </A>
  <A Code="A002" Label="A002">
    <A1 Code="002">
      <A44>A44</A44>
      <A55>A55</A55>
    </A1>
  </A>
</Document>

Please let me know.

Also How i can handle "Enumeration yielded no results" as count 0 in my return list since it's giving count>0 if this error occurs.

Upvotes: 4

Views: 10435

Answers (2)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236328

Result of query has type IEnumerable<List<IEnumerable<XElement>>>. But you are trying to assign it to IEnumerable<XElement>. Why? Because for each A element you are selecting list of A1 child elements. That gives you collection of lists.

You can use explicit result type to solve this issue. I.e. instead of IEnumerable<XElement> lv1s use var lvls. Or use actual lvls type: IEnumerable<List<IEnumerable<XElement>>> lvls.

Or if you want to get IEnumerable<XElement> then use SelectMany:

IEnumerable<XElement> lv1s = 
    rootElement.Descendants("A")
               .Where(lv1 => (string)lv1.Attribute("Code") == "A001" &&
                             (string)lv1.Attribute("Lable") == "A001")
               .SelectMany(lv1 => lv1.Descendants("A1")
                            .Where(ltd => (string)ltd.Attribute("Code") == "001")
                            .Select(ltd => ltd.Elements());

Or rewrite your query this way:

   IEnumerable<XElement> lv1s =  
         from lv1 in rootElement.Descendants("A")
         where (string)lv1.Attribute("Code") == "A001" &&
               (string)lv1.Attribute("Lable") == "A001"
         from ltd in lv1.Descendants("A1")
         where (string)ltd.Attribute("Code") == "001"
         from e in ltd.Elements()
         select e;

Returns following elements:

  <A11>A1</A11>
  <A22>A2</A22>
  <A33>A3</A33>

Upvotes: 3

Zev Spitz
Zev Spitz

Reputation: 15375

A suggestion: Instead of using .Value, cast as a string. Also, if your variable is in any case an IEnumerable<XElement> and not a List<XElement>, why do you need ToList?

XElement rootElement = XElement.Load(@"E:\Samples\TestConsole\TestConsoleApp\TestConsoleApp\XMLFile1.xml");
IEnumerable<XElement> lv1s = 
    from lv1 in rootElement.Descendants("A")
    where (string)lv1.Attribute("Code") == "A001" && (string)lv1.Attribute("Lable") == "A001"
    select (
        from ltd in lv1.Descendants("A1")
        where (string)ltd.Attribute("Code") == "001"
        select ltd.Elements()
    );

You have a nested LINQ query, and your query is also returning an IEnumerable<XElement>. Try removing the nested query, and returning a single element as the result of the query (the parentheses are only added for clarity):

IEnumerable<XElement> lv1s = (
    from lv1 in rootElement.Descendants("A")
    where (string)lv1.Attribute("Code") == "A001" && (string)lv1.Attribute("Lable") == "A001"
    from ltd in lv1.Descendants("A1")
    where (string)ltd.Attribute("Code") == "001"
    from e in ltd.Elements()
    select e
);

Also, if you are only searching one level deep, you can use Elements instead of Descendants:

IEnumerable<XElement> lv1s = (
    from lv1 in rootElement.Elements("A")
    where (string)lv1.Attribute("Code") == "A001" && (string)lv1.Attribute("Lable") == "A001"
    from ltd in lv1.Elements("A1")
    where (string)ltd.Attribute("Code") == "001"
    from e in ltd.Elements()
    select e
);

And if all you want are the values of those elements -- A1,A2 and A3 -- instead of XElement objects:

IEnumerable<string> lv1s = (
    from lv1 in rootElement.Elements("A")
    where (string)lv1.Attribute("Code") == "A001" && (string)lv1.Attribute("Lable") == "A001"
    from ltd in lv1.Elements("A1")
    where (string)ltd.Attribute("Code") == "001"
    from e in ltd.Elements()
    select (string)e
);

Upvotes: 1

Related Questions