public XmlNode GetNodeToMerge(XmlNode nodeToMatch, XmlNode parentToSearchIn, HashSet <XmlNode> acceptableTargets) { if (parentToSearchIn == null || nodeToMatch == null) { return(null); } var keyVal = nodeToMatch.Attributes[_key]; if (keyVal != null) { foreach (XmlNode node in parentToSearchIn.ChildNodes) { if (!acceptableTargets.Contains(node) || !(node is XmlElement)) { continue; } if (XmlUtilities.GetOptionalAttributeString(node, _key) == keyVal.Value) { return(node); } } } return(_backup.GetNodeToMerge(nodeToMatch, parentToSearchIn, acceptableTargets)); }
private XmlNode FindMatchingNode(XmlNode node, XmlNode otherParent, HashSet <XmlNode> acceptableTargets) { IFindNodeToMerge finder = _merger.MergeStrategies.GetMergePartnerFinder(node); var result = finder.GetNodeToMerge(node, otherParent, acceptableTargets); // This check allows implementations where there is only one possible match to ignore acceptableTargets // and just give us the one match from otherParent. If we don't want it, we discard it. if (!acceptableTargets.Contains(result)) { return(null); } return(result); }
/// <summary> /// Remove from ancestorKeepers any node that does not correspond to anything (both deleted) /// Remove from ancestorKeepers and theirKeepers any pair that correspond to each other but not to anything in ours. Report conflict (delete/edit) if pair not identical. /// Remove from ancestorKeepers and ourKeepers any pair that correspond to each other and are identical, but don't correspond to anything in theirs (they deleted) /// Report conflict (edit/delete) on any pair that correspond in ours and ancestor, but nothing in theirs, and that are NOT identical. (but keep them...we win) /// </summary> private void DoDeletions() { // loop over a copy of the list, since we may modify ancestorKeepers. List <XmlNode> loopSource = new List <XmlNode>(_childrenOfAncestorKeepers); var ourChildSet = new HashSet <XmlNode>(_ours == null ? new XmlNode[0] : _ours.ChildNodes.Cast <XmlNode>()); var theirChildSet = new HashSet <XmlNode>(_theirs == null ? new XmlNode[0] : _theirs.ChildNodes.Cast <XmlNode>()); foreach (XmlNode ancestorChild in loopSource) { ElementStrategy mergeStrategy = _merger.MergeStrategies.GetElementStrategy(ancestorChild); IFindNodeToMerge finder = mergeStrategy.MergePartnerFinder; XmlNode ourChild = finder.GetNodeToMerge(ancestorChild, _ours, ourChildSet); XmlNode theirChild = finder.GetNodeToMerge(ancestorChild, _theirs, theirChildSet); var extantNode = ancestorChild ?? ourChild ?? theirChild; if (extantNode is XmlCharacterData) { return; // Already done. } if (XmlUtilities.IsTextLevel(ourChild, theirChild, ancestorChild)) { new MergeTextNodesMethod(_merger, mergeStrategy, _skipInnerMergeFor, ref ourChild, _childrenOfOurKeepers, theirChild, _childrenOfTheirKeepers, ancestorChild, _childrenOfAncestorKeepers).DoDeletions(); } else if (ourChild == null) { // We deleted it. if (theirChild == null) { // We both deleted it. Forget it ever existed. // Route tested: MergeChildrenMethodTests. _merger.EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); } else { if (!XmlUtilities.AreXmlElementsEqual(ancestorChild, theirChild)) { // We deleted, they modified, report conflict. if (theirChild.NodeType == XmlNodeType.Element) { // Route tested (XmlMergerTests). _merger.ConflictOccurred( new RemovedVsEditedElementConflict(theirChild.Name, null, theirChild, ancestorChild, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(theirChild), _merger.MergeSituation.BetaUserId), theirChild); _skipInnerMergeFor.Add(theirChild); } else { // Never used. But then, there isn't plain text in an xml file. _merger.ConflictOccurred( new RemovedVsEditedTextConflict(null, theirChild, ancestorChild, _merger.MergeSituation, _merger.MergeSituation.BetaUserId)); _skipInnerMergeFor.Add(theirChild); } _childrenOfAncestorKeepers.Remove(ancestorChild); //review hatton added dec 2009, wanting whoever edited it to win (previously "we" always won) } else { //We deleted it, they didn't edit it. So just make it go away. // Route tested in TextElementMergeTests, MergeChildrenMethod_DiffOnlyTests, XmlMergerTests _merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild, theirChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); _childrenOfTheirKeepers.Remove(theirChild); } } } else if (theirChild == null) { // they deleted it (and we didn't) if (XmlUtilities.AreXmlElementsEqual(ancestorChild, ourChild)) { // We didn't touch it, allow their deletion to go forward, forget it existed. // Route tested (XmlMergerTests). _merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild, ourChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); _childrenOfOurKeepers.Remove(ourChild); } else { // We changed it, ignore their deletion and report conflict. if (ourChild.NodeType == XmlNodeType.Element) { // Route tested (XmlMergerTests). _merger.ConflictOccurred( new EditedVsRemovedElementConflict(ourChild.Name, ourChild, null, ancestorChild, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(ourChild), _merger.MergeSituation.AlphaUserId), ourChild); _skipInnerMergeFor.Add(ourChild); } else { // Never used. But then, there isn't plain text in an xml file. _merger.ConflictOccurred( new EditedVsRemovedTextConflict(ourChild, null, ancestorChild, _merger.MergeSituation, _merger.MergeSituation.AlphaUserId)); _skipInnerMergeFor.Add(ourChild); } } } } }