开发者

linq to xml enumerating over descendants

Hi trying to write a simple linq query from a tutorial I read. But i cannot seem to get it to work. I am trying to display both the address in the attached xml document, but can only display the first one. Can someone help me figure out why both aren't being printed. Thank you very much

<?xml version="1.0" encoding="utf-8" ?>
<Emails>
  <Email group="FooBar">
    <Subject>Test subject</Subject>
    <Content>Test Content</Content>
    <EmailTo>
      <Address>foo@bar.com</Address>
      <Address>bar@foo.com</Address>
    </EmailTo>
  </Email>
</Emails> 




    Dim steve = (From email In emailList.Descendants("Email") _
                Where (email.Attribute("group").Value.Equals("FooBar")) _
                Select content = email.Element("EmailTo").Descendants("Address"))开发者_如何学编程.ToList()



    If Not steve Is Nothing Then
        For Each addr In steve
            Console.WriteLine(addr.Value)
        Next
        Console.ReadLine()
    End If


Your current query returns a List<IEnumerable<XElement>>. That means you need two nested foreach loops: one to loop over the list, and another to loop over the content of the IEnumerable<XElement>.

Instead, you could update your LINQ query to use the Enumerable.SelectMany method and get to the addresses directly. In query format a SelectMany is represented by using a second from clause to indicate a subquery. This would resemble the following:

Dim query = (From email In emailList.Descendants("Email") _
            Where (email.Attribute("group").Value.Equals("FooBar")) _
            From addr In email.Element("EmailTo").Descendants("Address") _
            Select addr.Value).ToList()

If query.Any() Then
    For Each addr In query
        Console.WriteLine(addr)
    Next
End If

Also, the ToList isn't needed if you only want to iterate over the results and don't intend to use the result as a list for other purposes.

EDIT: to explain how this query works let's break it down in 2 parts:

First:

From email In emailList.Descendants("Email") _
Where (email.Attribute("group").Value.Equals("FooBar")) _

This queries for all <Email> nodes and only matches the ones that have a group attribute value of "FooBar".

Second:

From addr In email.Element("EmailTo").Descendants("Address") _
Select addr.Value

This is a subquery that continues where the first part (above) ended. It essentially is a way to further query the results of the original query. Here we query for all <Address> nodes and, finally, select their Value for the inner text of the nodes. The reason we need to do this is because Descendants("Address") returns a IEnumerable<XElement> containing all "Address" elements. We need to perform an additional query (or foreach) to iterate over those values and extract their values.

Another way to illustrate this is by breaking it down in 2 queries:

Dim query1 = From email In emailList.Descendants("Email") _
             Where (email.Attribute("group").Value.Equals("FooBar"))
             Select email.Element("EmailTo").Descendants("Address")
Dim query2 = query1.SelectMany(Function(addr) addr.Select(Function(a) a.Value))

Notice the use of SelectMany in query2. The Select in query2 is that additional effort to loop over the IEnumerable that I mentioned earlier. The original query is clearer than query1/query2, but I wrote them just to clarify the point.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜