C# Linq-XElement比较

C# Linq-XElement比较,c#,linq,xelement,C#,Linq,Xelement,我尝试比较两个xelements(),如下所示: XElement父项= <tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0"> <tcm:Item Title="070_Page" Modified="2016-01-06T18:08:36" CP1="-6185, Intro" CP2="-6182, Article Body" CP3="-14507, Article Body1" C

我尝试比较两个xelements(),如下所示:

XElement父项=

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
  <tcm:Item Title="070_Page" Modified="2016-01-06T18:08:36" CP1="-6185, Intro" CP2="-6182, Article Body" CP3="-14507, Article Body1" CP4="-14430, Article Body2" CP5="-14530, Article Body3" CP6="-7064, Article Body4" CP7="-14529, Article Body5" CP8="-7065, Article Body6" CPCount="8" /> 
  <tcm:Item Title="080_Page" Modified="2015-04-23T13:27:59" CP1="-6302, Intro" CP2="-6193, Article Body" CPCount="2" /> 
  <tcm:Item Title="Release Notes" Modified="2016-01-07T21:25:43" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" />
</tcm:ListItems>

XElement子项=

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
  <tcm:Item Title="070_Page" Modified="2016-06-06T19:36:35" CP1="-6185, Intro" CP2="-6147, Media & Delivery Intro" CP3="-6182, Article Body" CP4="-14507, Article Body1" CP5="-14430, Article Body2" CP6="-14530, Article Body3" CP7="-7064, Article Body4" CP8="-14529, Article Body5" CP9="-7065, Article Body6" CPCount="9" /> 
  <tcm:Item Title="080_Page" Modified="2016-02-09T21:03:32" CP1="-6302, Intro" CP2="-6193, Article Body" CPCount="2" /> 
  <tcm:Item Title="Release Notes" Modified="2016-02-09T21:03:33" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" /> 
  <tcm:Item Title="Release Notes1" Modified="2016-03-09T22:00:13" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" />
</tcm:ListItems>

我希望我的结果是(第一个有不同的CPCount,第二个是childItems中的新元素):

像素差=

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
  <tcm:Item Title="070_Page" Modified="2016-06-06T19:36:35" CP1="-6185, Intro" CP2="-6147, Media & Delivery Intro" CP3="-6182, Article Body" CP4="-14507, Article Body1" CP5="-14430, Article Body2" CP6="-14530, Article Body3" CP7="-7064, Article Body4" CP8="-14529, Article Body5" CP9="-7065, Article Body6" CPCount="9" />   
  <tcm:Item Title="Release Notes1" Modified="2016-03-09T22:00:13" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" />
</tcm:ListItems>


我试过了,但运气不好。我可以循环并得到结果,但有时列表可能很大(3000+)。有没有最好的方法来处理这个问题?

好的,下面是代码-在使用VS2015创建的控制台应用程序中(可能是非最佳的,但它可以工作-我最终得到了两个预期的元素-将重构作为家庭作业留给您):

类程序
{
//这只是为了方便地存储所有收集的数据
//还可以避免额外的字典查找和处理
内部类ElementAttributes
{
公共XElement元素{get;set;}
公共词典属性;
公共元素属性(XElement元素)
{
这个元素=元素;
this.Attributes=newdictionary();
}
}
静态void Main(字符串[]参数)
{
//从嵌入式资源加载XML元素
XElement parentItems=XElement.Parse(ResourceXML.parentItems);
XElement-childItems=XElement.Parse(ResourceXML.childItems);
XElement diff=XElement.Parse(@“”);
var parentDictionary=BuildDictionary(parentItems);
var childDictionary=BuildDictionary(childItems);
//执行差异
foreach(childDictionary.Keys中的字符串键)
{
元素属性parentElementAttributes;
if(parentDictionary.TryGetValue(键,out parentElementAttributes))
{
//在父级中找到标题/关键字,比较属性
foreach(childDictionary[key].Attributes中的var childAttribute)
{
var attributeName=childAttribute.Key;
var childAttributeValue=childAttribute.Value;
字符串parentAttributeValue;
if(parentElementAttributes.Attributes.TryGetValue(attributeName,out parentAttributeValue))
{
//在父级中找到属性,比较值
if(childAttributeValue==parentAttributeValue)
{
//值相等,比较其他属性
继续;
}
}
//父项没有此属性或
//子项中的不同值->在差异中显示
diff.Add(childDictionary[key].Element);
//不要比较其他属性
打破
}
//子级可能缺少仅在父级中的属性
//注意:您的示例没有提供此场景的用例
foreach(parentElementAttributes.Attributes中的var parentAttribute)
{
字符串attributeName=parentAttribute.Key;
如果(!childDictionary[key].Attributes.ContainsKey(attributeName))
{
//在父级中找到属性,但在子级中找不到
diff.Add(childDictionary[key].Element);
打破
}
}
}
其他的
{
//在父级中找不到,在差异中显示
diff.Add(childDictionary[key].Element);
}
}
}
私有静态字典构建字典(XElement元素)
{
XTCM=”http://www.tridion.com/ContentManager/5.0";
var resultDictionary=新字典();
foreach(element.Elements(tcm+“项”)中的XElement子元素)
{
var attributeDictionary=新元素属性(childElement);
foreach(childElement.Attributes()中的XAttribute属性)
{
字符串[]excludedColumns={“Title”,“Modified”};
if(excludedColumns.Contains(attribute.Name.LocalName))
{
继续;
}
attributeDictionary.Attributes.Add(attribute.Name.LocalName,attribute.Value);
}
resultDictionary.Add(childElement.Attribute(“Title”).Value,attributeDictionary);
}
返回结果字典;
}
}

所以您想使用Title属性作为键和其他属性-如果存在,只需进行比较,如果不匹配或缺少属性,则显示在结果列表中?您应该能够使用
字典
,其中第一个键是元素标题,第二个键是要比较的属性名。建立其中的两个,左和右,然后比较。谢谢你。。。是,标题将是主过滤器。。其他属性可能不同。。但我的结果应该基于:1)CPCount 2)如果子元素中有一个新元素,而父字典中不存在,这是正确的方法吗?会不会有一场糟糕的表演。。。linq有类似deepequals的东西吗?我会在回家后研究这个问题,我会尝试为您制作一个工作代码示例。。。谢谢你
class Program
{
    //this is just for convenient storage of all collected data
    //also to avoid additional dictionary lookups and processing
    internal class ElementAttributes
    {
        public XElement Element { get; set; }
        public Dictionary<string, string> Attributes;

        public ElementAttributes(XElement element)
        {
            this.Element = element;
            this.Attributes = new Dictionary<string, string>();
        }
    }

    static void Main(string[] args)
    {
        //loading XML elements from embedded resources
        XElement parentItems = XElement.Parse(ResourceXML.parentItems);
        XElement childItems = XElement.Parse(ResourceXML.childItems);

        XElement diff = XElement.Parse(@"<tcm:ListItems xmlns:tcm=""http://www.tridion.com/ContentManager/5.0"" ></tcm:ListItems>");

        var parentDictionary = BuildDictionary(parentItems);
        var childDictionary = BuildDictionary(childItems);

        //perform diff
        foreach (string key in childDictionary.Keys)
        {
            ElementAttributes parentElementAttributes;
            if (parentDictionary.TryGetValue(key, out parentElementAttributes))
            {
                //found Title/key in parent, compare attributes
                foreach (var childAttribute in childDictionary[key].Attributes)
                {
                    var attributeName = childAttribute.Key;
                    var childAttributeValue = childAttribute.Value;

                    string parentAttributeValue;
                    if (parentElementAttributes.Attributes.TryGetValue(attributeName, out parentAttributeValue))
                    {
                        //found attribute in parent, compare value
                        if(childAttributeValue == parentAttributeValue)
                        {
                            //values are equal, compare other attributes
                            continue;
                        }
                    }

                    //parent does not have this attribute OR
                    //different value in child -> show in diff
                    diff.Add(childDictionary[key].Element);

                    //do not compare other attributes
                    break;
                }

                //child may have missing attributes, which are in parent only
                //NOTE: your example does not present a use case for this scenario
                foreach (var parentAttribute in parentElementAttributes.Attributes)
                {
                    string attributeName = parentAttribute.Key;
                    if (!childDictionary[key].Attributes.ContainsKey(attributeName))
                    {
                        //attribute found in parent, but not in child
                        diff.Add(childDictionary[key].Element);
                        break;
                    }
                }
            }
            else
            {
                //not found in parent, show in diff
                diff.Add(childDictionary[key].Element);
            }
        }
    }


    private static Dictionary<string, ElementAttributes> BuildDictionary(XElement element)
    {
        XNamespace tcm = "http://www.tridion.com/ContentManager/5.0";

        var resultDictionary = new Dictionary<string, ElementAttributes>();
        foreach (XElement childElement in element.Elements(tcm + "Item"))
        {
            var attributeDictionary = new ElementAttributes(childElement);
            foreach (XAttribute attribute in childElement.Attributes())
            {
                string[] excludedColumns = {"Title", "Modified"};

                if (excludedColumns.Contains(attribute.Name.LocalName))
                {
                    continue;
                }

                attributeDictionary.Attributes.Add(attribute.Name.LocalName, attribute.Value);
            }
            resultDictionary.Add(childElement.Attribute("Title").Value, attributeDictionary);
        }
        return resultDictionary;
    }
}