Linq - XElement 比较
Linq - XElement Compare
我正在尝试比较两个 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 中的新元素):
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="Release Notes1" Modified="2016-03-09T22:00:13" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" />
</tcm:ListItems>
我试过 XMLDiff API 但没有成功。我可以遍历并获得结果,但有时列表可能会很大(3000+)。有没有最好的方法来处理这个问题?
好的,这是代码 - 在使用 VS2015 创建的控制台应用程序中(可能不是最佳的但它有效 - 我最终得到了两个预期的元素 - 将重构留给你作为家庭作业):
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;
}
}
我正在尝试比较两个 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 中的新元素):
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="Release Notes1" Modified="2016-03-09T22:00:13" CP1="-6303, Release Notes Intro" CP2="-6196, Release Notes Article Body" CPCount="2" />
</tcm:ListItems>
我试过 XMLDiff API 但没有成功。我可以遍历并获得结果,但有时列表可能会很大(3000+)。有没有最好的方法来处理这个问题?
好的,这是代码 - 在使用 VS2015 创建的控制台应用程序中(可能不是最佳的但它有效 - 我最终得到了两个预期的元素 - 将重构留给你作为家庭作业):
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;
}
}