LINQ to XML - 根据与另一个XElement相比的节点值过滤XElement?

时间:2014-04-29 15:35:05

标签: c# xml linq

我想从B中选择COMMISSION元素,其中每个COMMISSION元素的ID值不等于A COMMISSION元素。

这是我完整的主要方法:

    static void Main(string[] args)
    {
        XElement A = XElement.Parse(
            @"<CONTRACT>
                <COMMISSION>
                    <ID>1</ID>
                    <PRODUCTS>
                        <PRODUCT>A</PRODUCT>
                        <PRODUCT>B</PRODUCT>
                    </PRODUCTS>
                </COMMISSION>
                <COMMISSION>
                    <ID>2</ID>
                    <PRODUCTS>
                        <PRODUCT>C</PRODUCT>
                        <PRODUCT>D</PRODUCT>
                    </PRODUCTS>
                </COMMISSION>
                <COMMISSION>
                    <ID>3</ID>
                    <PRODUCTS>
                        <PRODUCT>E</PRODUCT>
                        <PRODUCT>F</PRODUCT>
                    </PRODUCTS>
                </COMMISSION>
            </CONTRACT>");

        XElement B = XElement.Parse(
            @"<CONTRACT>
                <COMMISSION>
                    <ID>3</ID>
                    <PRODUCTS>
                        <PRODUCT>E</PRODUCT>
                        <PRODUCT>F</PRODUCT>
                    </PRODUCTS>
                </COMMISSION>
            </CONTRACT>");

        // This *should* only return COMMISSION elements from B.
        // Rather, it returns the same B COMMISSION twice: once for the COMMISSION
        // element (ID=3) in B, and once for the COMMISSION element (ID=3) in A. 
        var bOnly =
            from excluded in A.Descendants("COMMISSION")
            let included = 
                from b in B.Descendants("COMMISSION")
                where b.Element("ID").Value != excluded.Element("ID").Value
                select b
            select new XElement("CONTRACT", included);

        // Print results 
        foreach (var v in bOnly)            
        {
            Console.WriteLine(v);
        }

        Console.ReadLine();
    }

正如我在代码中所述,而不是获得所需的输出:

            <CONTRACT>
                <COMMISSION>
                    <ID>3</ID>
                    <PRODUCTS>
                        <PRODUCT>E</PRODUCT>
                        <PRODUCT>F</PRODUCT>
                    </PRODUCTS>
                </COMMISSION>
            </CONTRACT>

我明白了:

        <CONTRACT>
            <COMMISSION>
                <ID>3</ID>
                <PRODUCTS>
                    <PRODUCT>E</PRODUCT>
                    <PRODUCT>F</PRODUCT>
                </PRODUCTS>
            </COMMISSION>
        </CONTRACT>
        <CONTRACT>
            <COMMISSION>
                <ID>3</ID>
                <PRODUCTS>
                    <PRODUCT>E</PRODUCT>
                    <PRODUCT>F</PRODUCT>
                </PRODUCTS>
            </COMMISSION>
        </CONTRACT>
        <CONTRACT/>

我不知道为什么带有ID = 3的COMMISSION会被返回两次。救命!谢谢。请记住,ID是我想要比较的唯一元素值。如果A的ID = 3 w /产品与B的ID = 3不同,那么我希望我的结果不显示任何内容。

我的最终解决方案:

           // Question: How do I only get COMMISSIONs from B that aren't in A?
        // Requirement: I only want to compare ID between A and B COMMISSION sets, 
        //   so if A ID=3 has products that are different from B ID=3, the query treats the
        //   two COMMISSIONs as the same so long as their ID is the same.
        // Answer: (Steps 1 thru 3)        

        // Step 1) Get COMMISSIONs from B equalling COMMISSIONs from A on ID       
        var same =
            from a in A.Descendants("COMMISSION")
            join b in B.Descendants("COMMISSION")
            on a.Element("ID").Value equals b.Element("ID").Value
            select a;

        // Step 2) Get all COMMISSIONs from B
        var all = from b in B.Descendants("COMMISSION")
                    select b;

        // Step 3) Get COMMISSIONs that are only in B
        var different = all.Cast<XNode>().Except(same.Cast<XNode>(), new XNodeEqualityComparer());

        // Print results 
        foreach (var v in different)            
        {
            Console.WriteLine(v);
        }

1 个答案:

答案 0 :(得分:1)

我已将您的LINQ查询更改为以下

var bOnly =
    from a in A.Descendants("COMMISSION")
    join b in B.Descendants("COMMISSION")
    on a.Element("ID").Value equals b.Element("ID").Value
    select a;

现在输出看起来不错,没有重复:

<COMMISSION>
    <ID>3</ID> 
    <PRODUCTS>
        <PRODUCT>E</PRODUCT> 
        <PRODUCT>F</PRODUCT> 
    </PRODUCTS>
</COMMISSION>

此外,我修复了您的示例中的查询,它现在也正常工作:

var bOnly =
    from b in B.Descendants("COMMISSION")
    let same =
        from a in A.Descendants("COMMISSION")
        where a.Element("ID").Value == b.Element("ID").Value
        select b
    select new XElement("CONTRACT", same);