LINQ to XML 查询属性

5
使用LINQ to XML,这是我的XML示例。
<shows>
 <Show Code="456" Name="My Event Name">
   <Event Code="2453" VenueCode="39" Date="2010-04-13 10:30:00" /> 
   <Event Code="2454" VenueCode="39" Date="2010-04-13 13:30:00" /> 
   <Event Code="2455" VenueCode="39" Date="2010-04-14 10:30:00"  /> 
   <Event Code="2456" VenueCode="39" Date="2010-04-14 13:30:00" /> 
   <Event Code="2457" VenueCode="39" Date="2010-04-15 10:30:00" /> 
 </Show>

 <Show... />
 <Show... />
</shows>

如何返回指定演出的日期列表?我会在查询字符串中传递演出代码(“456”),并希望将所有日期/时间作为列表返回。

这是我目前的代码:

XDocument xDoc = XDocument.Load("path to xml");

            var feeds = from feed in xDoc.Descendants("Show")
                        where feed.Attribute("Code").Equals("456")
                        select new
                        {
                            EventDate = feed.Attribute("Date").Value
                        };

            foreach(var feed in feeds)
            {
                Response.Write(feed.EventDate + "<br />");
            }

但是我没有收到任何结果。

1
@reinierpost:不,他正在尝试迭代Show="456"的子事件标签。值"2456"是一个事件代码。;-) - Prutswonder
@Prutswonder - 你是正确的! - kb.
@kb:正如我在答案中所指出的,您正在尝试在 Show 中查找 Date 属性,而不是在 Event 中查找。您可能需要另一个“from”子句... - Jon Skeet
我以为“Show”不会是它自己的.Descendant,但我又怎么知道呢……我只是路过。 - reinierpost
3个回答

10

该属性不会“等于”“456”——它是一个属性,而不是字符串。但是,如果您先将其转换为字符串,它将起作用。

var feeds = from feed in xDoc.Descendants("Show")
            where (string)feed.Attribute("Code") == "456"
            select new
            {
                EventDate = feed.Attribute("Date").Value
            };

另一种选择是使用int来确保它是数字:
var feeds = from feed in xDoc.Descendants("Show")
            where (int) feed.Attribute("Code") == 456
            select new
            {
                EventDate = feed.Attribute("Date").Value
            };

编辑:好的,我现在已经有一个简短但完整的程序来展示它的工作原理。

请注意,您原始的代码只有在“Show”元素具有“Date”属性时才能正常工作 - 而在您的示例XML中没有该属性。请注意,它试图从“Show”元素而不是“Event”元素中获取“Date”。我不确定您真正想在这里做什么,因此我已将代码更改为仅转换为DateTime?。以下代码有效,并打印1(即找到与代码匹配的单个Show元素):

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

public static class Test
{    
    static void Main(string[] args)
    {
        XDocument xDoc = XDocument.Load("shows.xml");
        var feeds = from feed in xDoc.Descendants("Show")
                    where (int) feed.Attribute("Code") == 456
                    select new
                    {
                        EventDate = (DateTime?) feed.Attribute("Date")
                    };

        Console.WriteLine(feeds.Count());
    }
}

如果你真的想找到展示中的每个事件日期,你需要另一个“from”子句来使其在展示内迭代事件:
var events = from feed in xDoc.Descendants("Show")
             where (int) feed.Attribute("Code") == 456
             // We can't use event as an identifier, unfortunately
             from ev in feed.Elements("Event")
             select new
             {
                 EventDate = (DateTime?) ev.Attribute("Date")
             };

好的,我已经纠正了我的错误,现在我正在评估属性的值,但仍然没有得到结果。正如“reinierpost”所指出的:“不,他试图迭代来自Show =“456”的子事件标记。值“2456”是一个事件代码。”这是正确的。我想返回所有显示代码“456”的日期。因此,我需要遍历“Event”元素。 - kb.
@kb:请看我的编辑。不清楚你想用日期做什么,但是这段代码确实会找到节目... - Jon Skeet
谢谢Jon,你上面的帖子解决了我的问题!我一直在想可能需要使用一个额外的where子句来遍历事件日期!谢谢。 - kb.
不错的技巧来反转等于号。我喜欢它。但是同样可以使用运算符==,而不需要任何技巧,或者我错过了什么? - Stéphane
@serbrech:不,我一点也没有漏掉任何东西。我太傻了 :) 我会编辑的。 - Jon Skeet

6

请将这一行修改为:

where feed.Attribute("Code").Equals("456")

致:

where feed.Attribute("Code").Value.Equals("456")

否则,您将比较属性作为对象而不是属性的值。

2
这是另一种做法:
   var nodes = xmlFile.Nodes()
  .OfType<XElement>()
    .DescendantNodes()
  .OfType<XElement>()
    .Where(x => x.Name.LocalName == "Event" && x.Attribute("Code").Value.Contains("456"));
foreach (var node in nodes)
{
    Console.WriteLine(node.Attribute("Code"));
}   

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