Linq to XML:获取存在于不同层级的属性

4

我正在尝试编写一个Linq to XML查询,用于检索关键字并包括一个属性(mediatype)。

考虑以下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>

有照片元素和视频元素。每个元素都有一个mediatype属性。

我想要查询每个关键字及其媒体类型。

类似于这样的查询结果...

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属性上。这个属性存在于不同的级别上,而不是关键字。

3个回答

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的节点,然后对于这些元素中的每一个,您需要获取其中的关键字。使用SelectMany扩展方法将结果展平,最终只得到一个集合。


这就是答案,它告诉我我还有很多关于Linq to Xml需要学习。谢谢! - codingguy3000
不客气 @codingguy3000,使用linq有多种方法可以实现它,一旦你知道如何使用它,它就非常强大,我强烈建议你学习更多关于它的知识,愉快编码 ;) - ocuenca

1
你也可以这样做:

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

只要您知道带有mediatypevideo元素总是祖先元素,如果不知道,您应该使用类似Ancestors()的方法来查找它。

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

但是使用 SelectMany 的解决方案非常优雅。 - Anton Komyshan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接