作为Linq的新手,我花了太多时间在这上面,所以是时候向专家们寻求一些指示了:)
总之,我想使用两个where和一个group by子句来过滤输入,创建我可以投入的输出
new <SMO<SMO<Plane>>(id, items)
类型集合。 (SMO是我自己的ObservableCollection实现,通过给出Title和'root'XElements来实例化。)
我的XML输入类似于此;
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<id>manifest id</id>
<locale>US</locale>
<plane>
<id>First</id>
<definition>
<description>plane description</description>
<type>plane type</type>
<item>
<name>Item 1</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>instant</c>
<p1>delivery parameter 1</p1>
<p2>delivery parameter 2</p2>
</ondelivery>
</item>
<item>
<name>Item 2</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>email</c>
<p1>delivery parameter 1</p1>
</ondelivery>
</item>
</definition>
</plane>
<plane>
<id>Second</id>
<definition>
<description>plane description</description>
<type>plane type</type>
<item>
<name>Item 1</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>instant</c>
<p1>delivery parameter 1</p1>
<p2>delivery parameter 2</p2>
</ondelivery>
</item>
<item>
<name>Item 2</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>email</c>
<p1>delivery parameter 1</p1>
</ondelivery>
</item>
<item>
<name>Item 3</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>instant</c>
<p1>delivery parameter 1</p1>
<p2>delivery parameter 1</p2>
<p3>delivery parameter 1</p3>
</ondelivery>
</item>
</definition>
</plane>
</manifest>
基本上,每个平面都有一个定义,其中包含任意数量的 item 。每个项包含一个 c ,后跟任意数量的 p N.
我需要做的是根据它的 id 过滤掉一个平面。通过运行类似的东西,这是微不足道的。
var oput = (from c in doc.Element("manifest").Elements("plane")
where (string)c.Element("id") == "Second"
select c);
当我必须根据每个项的 c 属性进一步过滤此问题时,会出现问题(但同时有一个完整的平面要使用的元素)。例如,从上面的源代码我需要从 plane “second”中拉出所有项的 c 等于“instant”。
从此我希望/需要类似于
的输出<?xml version="1.0" encoding="utf-8"?>
<manifest>
<id>manifest id</id>
<locale>US</locale>
<plane>
<id>Second</id>
<definition>
<description>plane description</description>
<type>plane type</type>
<item>
<name>Item 1</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>instant</c>
<p1>delivery parameter 1</p1>
<p2>delivery parameter 2</p2>
</ondelivery>
</item>
<item>
<name>Item 3</name>
<condition>item condition</condition>
<description>item description</description>
<ondelivery>
<c>instant</c>
<p1>delivery parameter 1</p1>
<p2>delivery parameter 1</p2>
<p3>delivery parameter 1</p3>
</ondelivery>
</item>
</definition>
</plane>
</manifest>
以XElement的形式(因为我正在创建一个 new Plane 类,它将此作为输入)。
到目前为止我提出的最好的是
var oput = (from c in doc.Element("manifest").Elements("plane")
where (string)c.Element("id") == "Second"
from d.Elements("definition").Elements("item").Elements("c")
where (string)d.Element("c") == "instant"
select d);
它可以正确过滤,但它给我的输出是可以理解的,是 ondelivery 的IEnumerable。
我尝试过使用c,d.Parent,new XElement(“plane”,d.Parent.Parent.Parent.Element(“id”),d.Parent))等实际选择。在,但我完全无法得到我想要的那种输出。
作为奖励,我想根据 plane * id *同时对这些进行分组。我已经掌握了group by子句,但不知道如何格式化它给出的输出。理想情况下,我需要输出为(String,IEnumerable)像(“Second”,(XElement(Item 1),XElement(Item 2)))而我似乎总是以(IEnumerable(String,IEnumerable))结束)外部IEnumerable的项目数为1。
答案 0 :(得分:0)
我只会使用原始查询选择plane
元素,然后添加一些代码来删除不需要的item
元素,如下所示:
var oput = (from c in doc.Descendants("plane")
where (string)c.Element("id") == "Second"
select c);
foreach (var plane in oput)
{
foreach (var item in plane.Descendants("item").Where((x) => x.Descendants("c").First().Value != "instant").ToList() )
{
item.Remove();
}
Console.WriteLine(plane); // or whatever you need to do with each plane.
}
对项目循环调用ToList()
非常重要,因为没有它,foreach
会在其中一个项目被删除时中断。基本上调用ToList()
会使列表的副本更改为Remove
方法不会修改。