如何使用linq to xml在两个不同的xml文件中查找匹配的节点

时间:2013-11-26 13:47:51

标签: c# linq linq-to-xml linqpad

我刚问了另一个问题here,答案就在那里。

但这解决了本质上是语法问题的问题。现在我需要实际解决方案的帮助。

这是与上一个问题相同的代码(已修复并添加了内容)。

XElement FILE1 = XElement.Load (@"..\FILE1.XML");
XElement FILE2 = XElement.Load (@"..\FILE2.XML");

var orders = from file1 in FILE1.Descendants("Players").Elements("Player")
                        select new {
                            name=new {
                                clientID=ulm.Element("ClientID").Value,
                                firstName=file1.Element("FirstName").Value,
                                lastName=file1.Element("LastName").Value
                            }                           
                        };

var orders2 = 
             from file2 in FILE2.Descendants("Players").Elements("Player")
                        select new {
                            name=new {
                                clientID=ulm.Element("ClientID").Value,
                                firstName=file2.Element("FirstName").Value,
                                lastName=file2.Element("LastName").Value
                            }                           
                        };

var matchingResults = from i in orders from j in orders2 where (i.name.firstName==j.name.firstName && i.name.lastName==j.name.lastName)
                            select i;
matchingResults.Dump()     

为了让它变得有趣,我在尝试匹配它们之前为每个序列结果添加了一个ClientID。

我需要知道的是来自orders2的玩家节点中的订单EXISTS的玩家节点。还是不存在?理想情况下,我也可以选择NOT EXISTS / EXISTS检查的选择标准。 (LastName,或FirstName&& LastName,或仅限ClientID等)

我没有想法如何解决这个问题。谢谢你的帮助。

2 个答案:

答案 0 :(得分:0)

  • 使用Enumerable.IntersectEnumerable.Except
  • 使用具体类型而不是匿名类型。
  • 为了能够选择选择标准,您可以创建参数化IEqualityComparer<Client>

    class Client
    {
        public string ClientID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
    [Flags]
    enum Criteria { 
        ClientID, FirstName, LastName
    }
    
    class ClientEqualityComparer : IEqualityComparer<Client> {
    
        private Criteria criteria;
        public ClientEqualityComparer(Criteria criteria) {
            this.criteria = criteria;
        }
    
        #region IEqualityComparer<Client> Membres
    
        public bool Equals(Client x, Client y)
        {
            if (criteria.HasFlag(Criteria.ClientID) && x.ClientID != y.ClientID)
                return false;
            if (criteria.HasFlag(Criteria.FirstName) && x.FirstName != y.FirstName)
                return false;
            if (criteria.HasFlag(Criteria.LastName) && x.LastName != y.LastName)
                return false;
            return true;
        }
    
        public int GetHashCode(Client obj)
        {
            int hash = 17;
            if (criteria.HasFlag(Criteria.ClientID))
                hash = hash * 31 + obj.ClientID;
            if (criteria.HasFlag(Criteria.FirstName))
                hash = hash * 31 + obj.FirstName;
            if (criteria.HasFlag(Criteria.LastName))
                hash = hash * 31 + obj.LastName;
        }
    
        #endregion
    }
    
    static void Main(string[] args)
    {
    
        IEnumerable<Client> orders;
        IEnumerable<Client> orders2;
        //...
        var matchingIdFn = orders.Intersect(orders2, 
            new ClientEqualityComparer(Criteria.ClientID | Criteria.FirstName));
    
        var matchingIdFnLn = orders.Intersect(orders2, 
            new ClientEqualityComparer(Criteria.ClientID | Criteria.FirstName | Criteria.LastName));
    
        var different = orders.Except(orders2, new ClientEqualityComparer(Criteria.ClientID | Criteria.FirstName));            
    }
    

var orders = from file1 in FILE1.Descendants("Players").Elements("Player")
                    select new Client{
                        ClientID=ulm.Element("ClientID").Value,
                        FirstName=file1.Element("FirstName").Value,
                        LastName=file1.Element("LastName").Value                        
                    };

答案 1 :(得分:0)

我的第二个Ahmed KRAIEM建议使用IntersectExcept

这是另一个让你可以使用任意lambda进行比较的解决方案:

void Main()
{
XElement FILE1 = XElement.Parse(
@"<Root>
    <Players>
        <Player><ClientId>1</ClientId><FirstName>Bob</FirstName><LastName>Smith</LastName></Player>
        <Player><ClientId>2</ClientId><FirstName>John</FirstName><LastName>Smith</LastName></Player>
    </Players>
</Root>");
    XElement FILE2 = XElement.Parse(
@"<Root>
    <Players>
        <Player><ClientId>2</ClientId><FirstName>Bob</FirstName><LastName>Smith</LastName></Player>
        <Player><ClientId>3</ClientId><FirstName>Mike</FirstName><LastName>Smith</LastName></Player>
    </Players>
</Root>");

var orders = from file1 in FILE1.Descendants("Players").Elements("Player")
                    select new Player(Int32.Parse(file1.Element("ClientId").Value), file1.Element("FirstName").Value, file1.Element("LastName").Value);

var orders2 = from file2 in FILE2.Descendants("Players").Elements("Player")
                    select new Player(Int32.Parse(file2.Element("ClientId").Value), file2.Element("FirstName").Value, file2.Element("LastName").Value);

//orders.Dump();
//orders2.Dump();

var exists = orders2.Intersect(orders, new LambdaEqualityComparer<Player>((i, j) => i.FirstName == j.FirstName && i.LastName == j.LastName));
// or
//var exists = orders2.Intersect(orders, new LambdaEqualityComparer<Player>((i, j) => i.ClientId == j.ClientId));
exists.Dump();

var notExists = orders2.Except(orders, new LambdaEqualityComparer<Player>((i, j) => i.FirstName == j.FirstName && i.LastName == j.LastName));
// or
//var notExists = orders2.Except(orders, new LambdaEqualityComparer<Player>((i, j) => i.ClientId == j.ClientId));
notExists.Dump();
}

public class Player
{
public int ClientId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }

public Player(int clientId, string firstName, string lastName)
{
    ClientId = clientId;
    FirstName = firstName;
    LastName = lastName;
}
}

public class LambdaEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> EqualityComparer { get; set; }

public LambdaEqualityComparer(Func<T, T, bool> equalityComparer)
{
    EqualityComparer = equalityComparer;
}

public bool Equals(T x, T y)
{
    return EqualityComparer(x, y);
}

public int GetHashCode(T obj)
{
    // If the hash codes are different, then Equals never gets called. Make sure Equals is always called by making sure the hash codes are always the same.
    // (Underneath, the .NET code is using a set and the not (!) of a Find method to determine if the set doesn't already contain the item and should be added.
    // Find is not bothering to call Equals unless it finds a hash code that matches.)
    //return obj.GetHashCode();
    return 0;
}
}

请注意,如果您不想创建Player对象,则可以将其完全删除,在ordersorders2中填充匿名对象,就像之前一样,并创建一个new LambdaEqualityComparer<dynamic>而不是new LambdaEqualityComparer<Player>,但由于动态反射调用会慢一些。