LINQ to XML, перечисление потомков - PullRequest
1 голос
/ 13 января 2011

Привет, я пытаюсь написать простой запрос linq из учебника, который я прочитал.Но я не могу заставить его работать.Я пытаюсь отобразить оба адреса в прикрепленном XML-документе, но могу отобразить только первый.Может кто-нибудь помочь мне понять, почему оба не печатаются.Большое спасибо

<?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

1 Ответ

2 голосов
/ 13 января 2011

Ваш текущий запрос возвращает List<IEnumerable<XElement>>. Это означает, что вам нужно два вложенных цикла foreach: один для циклического перемещения по списку, а другой для циклического перемещения по содержимому IEnumerable<XElement>.

Вместо этого вы можете обновить свой запрос LINQ, чтобы использовать метод Enumerable.SelectMany, и напрямую получить адреса. В формате запроса SelectMany представляется с использованием второго предложения from для указания подзапроса. Это будет выглядеть следующим образом:

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

Кроме того, ToList не требуется, если вы хотите перебирать результаты и не намерены использовать результат в качестве списка для других целей.

РЕДАКТИРОВАТЬ: чтобы объяснить, как работает этот запрос, давайте разбить его на 2 части:

Первый:

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

Опрашивает все <Email> узлы и совпадает только с теми, которые имеют атрибут group атрибута "FooBar".

Второе:

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

Это подзапрос, который продолжается там, где закончилась первая часть (выше). По сути, это способ дальнейшего запроса результатов исходного запроса. Здесь мы запрашиваем все <Address> узлы и, наконец, выбираем их Value для внутреннего текста узлов. Причина, по которой мы должны это сделать, заключается в том, что Descendants("Address") возвращает IEnumerable<XElement>, содержащий все элементы "Address". Нам нужно выполнить дополнительный запрос (или foreach), чтобы перебрать эти значения и извлечь их значения.

Другой способ проиллюстрировать это - разбить его на 2 запроса:

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))

Обратите внимание на использование SelectMany в query2. Select в query2 - это дополнительная попытка перебрать IEnumerable, о которой я упоминал ранее. Исходный запрос более понятен, чем query1 / query2, но я написал их просто для пояснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...