这对我来说是个脑筋急转弯:
假设我有类似以下的XML数据:
<?xml version="1.0"?>
<site>
<open_auction id="open_auction0">
<initial>25.39</initial>
<reserve>67.91</reserve>
<bidder>
<date>09/27/1999</date>
<time>18:47:09</time>
<personref person="person308"/>
<increase>18.00</increase>
</bidder>
<bidder>
<date>06/03/2000</date>
<time>17:47:49</time>
<personref person="person942"/>
<increase>19.50</increase>
</bidder>
<bidder>
...
</bidder>
<current>202.39</current>
<itemref item="item2"/>
<seller person="person573"/>
<annotation>
<author person="person128"/>
<description>
<parlist>
<listitem>
<text>
niece <keyword> till banqueting little unkindly </keyword>
</text>
</listitem>
<listitem>
<text>
emilia jack standards
</text>
</listitem>
</parlist>
</description>
<happiness>1</happiness>
</annotation>
<quantity>1</quantity>
<type>Regular</type>
<interval>
<start>12/23/2001</start>
<end>11/11/2000</end>
</interval>
</open_auction>
<open_auction id="open_auction1">
...
</open_auction>
<open_auction id="open_auction2">
...
</open_auction>
</site>
您可以从www.megamatz.de/auction.xml下载完整且更大(约5MB)的测试文件
我需要确定某个特定人(Person1)在另一个人(Person2)之前发出出价的所有open_auctions的ID。 Person1的“bidder”节点意义上的“之前”在一个open_auction中的Person2的“bidder”节点之前发生,因此它不涉及日期或时间。
这个问题的XPath-Query可能会更好地解释问题:
let $auction := doc("auction.xml") return
for $b in $auction/site/open_auctions/open_auction
where
some $pr1 in $b/bidder/personref[@person = "person20"],
$pr2 in $b/bidder/personref[@person = "person51"]
satisfies $pr1 << $pr2
return <history>{$b/reserve/text()}</history>
我知道我需要某种嵌套查询,但我不能直接使用这个Linq概念和这些XElement。因此,我不仅对解决方案感兴趣,而且还理解任何(),包含()的概念,以及用linq处理这些查询的其他内容。
我真的很绝望,需要一些帮助,我一直在寻找整个晚上的尝试,但我根本无法理解,没有任何作用。
已编辑添加
很抱歉再次提问,但不,它不起作用。我尝试过并试过,这非常好,因为我学到了很多东西。我感觉我几乎找到了答案,但是当涉及到“ElementAfterSelf”时,我会在这个复杂查询的上下文中使用一些暗示和解释。这是我的方法,我根据我从Jon Skeets得到的答案得出的答案:
List<XElement> = doc.Descendants("open_auction")
.Where(x => x.Element("bidder") != null && x.Elements("bidder")
.Any(b => b.Elements("personref")
.First(c => c.IsBidder("person540"))
.ElementsAfterSelf("bidder").Any(d => d.IsBidder("person1068"))
)).ToList();
但它也不起作用。但是...:
List<XElement> j = XMarkXML.Element("site").Element("open_auctions").Elements("open_auction")
.Where(x => x.Element("bidder") != null && x.Elements("bidder")
.Any(b => b.Elements("personref")
.Any(c => c.IsBidder("person540")) //I changed First with Any
//.ElementsAfterSelf().Any(d => d.IsBidder("person1068")) //and commented the last part out
)).ToList();
......至少提出3“open_auction”,其中“person540”是投标人。要在我的测试文件中具体,它是id =“open_auction11”,其中“person1068”在“person540”之后出价。
我是从内心深处问,有人可以尝试一下Testfile。我将其上传到www.megamatz.de/auction.xml。在文件内部,公开拍卖的路径是:元素(“站点”)。元素(“open_auctions”)。元素(“open_auction”)
答案 0 :(得分:3)
// Extension methods
internal static bool IsBidder(this XElement bidder, string person)
{
return (string) bidder.Element("personref")
.Attribute("person") == person;
}
internal static IEnumerable<XElement> ElementsAfterFirst
(this IEnumerable<XElement> source, XName name)
{
var first = source.FirstOrDefault();
if (first != null)
{
foreach (var element in first.ElementsAfterSelf(name))
{
yield return element;
}
}
}
var query = doc
.Descendants("open_auction")
.Where(x => x.Elements("bidder")
// All the person20 bids...
.Where(b => b.IsBidder("person20"))
// Now project to bids after the first one...
.ElementsAfterFirst("bidder")
// Are there any from person51? If so, include this auction.
.Any(b => b.IsBidder("person51"))
);
第二种扩展方法也可以写成:
internal static IEnumerable<XElement> ElementsAfterFirst
(this IEnumerable<XElement> source, XName name)
{
var first = source.FirstOrDefault();
return first == null ? new XElement[0] : first.ElementsAfterSelf(name);
}
它稍微改变了时间,但在这种特殊情况下不应该有任何区别......
答案 1 :(得分:0)
很多Jon!您的代码帮助我学习了Linq to XML的这个概念 好的,我已经做了一个没有任何辅助方法的查询,这很好。我已经形成了一些不寻常的东西,但它可能会帮助像我这样的其他类似的人看看这里发生了什么:
List<XElement> i = XMarkXML.Element("site").Element("open_auctions").Descendants("open_auction")
.Where(x => (x.Element("bidder") != null )
&&
(x.Elements("bidder").Any(b => (b.Element("personref").Attribute("person").Value == "person540")))
&&
(
x.Elements("bidder").Where(
b1 => (b1.Element("personref").Attribute("person").Value == "person540")
).First().ElementsAfterSelf("bidder").Any(
b2 => (b2.Element("personref").Attribute("person").Value == "person1068")
)
)
).ToList();
在集合上执行操作时,重要的是内部有一些内容,因此检查Collection.Count()!= 0是否很重要。之后可以进行查询。