2017-02-08 6 views
4

Я пытаюсь написать Linq для запроса XML, который тянет обратно ключевое слово, и включает в себя атрибут (MEDIATYPE)Linq для XML заваливая атрибут, который существует на другом уровне

Рассмотрим следующие данные XML ...

<?xml version="1.0" encoding="utf-8"?> 
<media> 
    <photos>   
     <photo mediatype="photo" photographer="Jag_cz" description="Colored splashes in abstract shape, isolated on white background" id="16" name="50623755_F.jpg" folder="HR Headset"> 
      <keywords> 
       <keyword>fish</keyword> 
       <keyword>abstract</keyword>   
      </keywords> 
     </photo> 
    </photos> 
    <videos> 
     <video mediatype="video" description="Bear by a stream" folder="streamfolder" name="stream.mp4"> 
      <keywords> 
       <keyword>stream</keyword> 
       <keyword>river</keyword> 
       <keyword>water</keyword> 
      </keywords> 
     </video> 
     <video mediatype="video" description="Stream with a bear" folder="bearfolder" name="bear.mp4"> 
      <keywords> 
       <keyword>salmon</keyword> 
       <keyword>fish</keyword> 
      </keywords> 
     </video> 
    </videos> 
</media> 

Есть фотоэлементы и видеоэлементы. Каждый элемент имеет атрибут mediattype.

Я хочу вернуть запрос каждого ключевого слова с его медиа-типом.

Что-то вроде этого ..

mediatype keyword 
--------- -------    
photo  fish 
photo  abstract 
video  stream 
video  river 
video  water 
video  salmon 
video  fish 

Я был в состоянии отступить ключевые слова с помощью следующего кода ...

using System; 
using System.Xml.Linq; 
using System.Linq; 

class Program 
{ 
    public static void Main(string[] args) 
    { 
     String strPath = @"C:\videodata\media.xml"; 

     XElement xEle = XElement.Load(strPath); 

     var keywordquery = from k in xEle.Descendants("keyword") 
          select new 
           { 
            keyword = (string)k.Value 
           }; 

     foreach (var k in keywordquery) 
     { 
      Console.WriteLine(k.keyword); 
     } 

     Console.WriteLine("Press <enter> to continue"); 
     Console.ReadLine(); 
    } 
} 

Однако, я застрял на отходила MEDIATYPE атрибут. Этот атрибут существует на другом уровне, чем ключевое слово.

ответ

4

Вы можете сделать что-то вроде этого:

var query= xEle.Descendants().Where(e=>e.Name=="photo" || e.Name=="video") 
           .SelectMany(e=>e.Descendants("keyword") 
               .Select(x=>new {mediatype=e.Name, 
                   keyword=x.Value 
                  })); 

В общем, вы выбираете сначала все узлы с именем photovideo и, а затем на каждый из этих элементов вы должны получить ключевые слова inside.Using SelectMany метод расширения вы расплющить результат, чтобы наконец получить только одну коллекцию

+0

Это ответ, и он просто показывает мне, что мне еще многое предстоит узнать о Linq для Xml. Спасибо! – codingguy3000

+0

Добро пожаловать @ codingguy3000, есть несколько способов сделать это с помощью linq, он действительно мощный, как только вы знаете, как его использовать, я определенно рекомендую вам узнать больше об этом, счастливая codding;) – octavioccl

0

Если у вас есть стабильная структура файла XML можно использовать простой выбор:

var keywordquery = xEle.Descendants("keyword") 
    .Select(x => new { MediaType = x.Parent?.Parent.Attribute("mediatype").Value, KeyWords = x.Value}); 

    foreach (var k in keywordquery) 
    { 
    Console.WriteLine($"{k.MediaType} | {k.KeyWords}"); 
    } 

    Console.WriteLine("Press <enter> to continue"); 
    Console.ReadLine(); 
+0

Но решение с 'SelectMany' действительно элегантны. –

1

Вы можете сделать это, а также:

var keywordquery = from k in xEle.Descendants("keyword") 
        select new 
        { 
         keyword = (string)k.Value, 
         mediatype = (string)k.Parent.Parent.Attribute("mediatype") 
        }; 

До тех пор, как вы знаете, что video элемент с mediatype всегда будет прародитель элементом. Если нет, вы можете использовать что-то вроде Ancestors(), чтобы найти его.

+0

Ум взорван !!!!! – codingguy3000

 Смежные вопросы

  • Нет связанных вопросов^_^