public void ReportDifferencesToListener() { foreach (XmlNode node in _parentDom.SafeSelectNodes("lift/entry")) { string strId = LiftUtils.GetId(node); if (!_parentIdToNodeIndex.ContainsKey(strId)) { _parentIdToNodeIndex.Add(strId, node); } else { System.Diagnostics.Debug.WriteLine(String.Format("Found ID multiple times: {0}", strId)); } } foreach (XmlNode childNode in _childDom.SafeSelectNodes("lift/entry")) { try { ProcessEntry(childNode); } catch (Exception error) { EventListener.ChangeOccurred(new ErrorDeterminingChangeReport(_parentFileInRevision, _childFileInRevision, null, childNode, error)); } } //now detect any removed (not just marked as deleted) elements foreach (XmlNode parentNode in _parentIdToNodeIndex.Values) // _parentDom.SafeSelectNodes("lift/entry")) { try { if (!_processedIds.Contains(LiftUtils.GetId(parentNode))) { EventListener.ChangeOccurred(new XmlDeletionChangeReport(_parentFileInRevision, parentNode, null)); } } catch (Exception error) { EventListener.ChangeOccurred(new ErrorDeterminingChangeReport(_parentFileInRevision, _childFileInRevision, parentNode, null, error)); } } }
private void ProcessEntry(XmlNode child) { string id = LiftUtils.GetId(child); XmlNode parent = null; // = LiftUtils.FindEntryById(_parentDom, id); _parentIdToNodeIndex.TryGetValue(id, out parent); string path = string.Empty; if (_childFileInRevision != null && !string.IsNullOrEmpty(_childFileInRevision.FullPath)) { path = Path.GetFileName(_childFileInRevision.FullPath); } string url = LiftUtils.GetUrl(child, path); if (parent == null) //it's new { //it's possible to create and entry, delete it, then checkin, leave us with this //spurious deletion messages if (string.IsNullOrEmpty(XmlUtilities.GetOptionalAttributeString(child, "dateDeleted"))) { EventListener.ChangeOccurred(new XmlAdditionChangeReport(_childFileInRevision, child, url)); } } else if (LiftUtils.AreTheSame(child, parent)) //unchanged or both made same change { } else //one or both changed { if (!string.IsNullOrEmpty(XmlUtilities.GetOptionalAttributeString(child, "dateDeleted"))) { EventListener.ChangeOccurred(new XmlDeletionChangeReport(_parentFileInRevision, parent, child)); } else { //enhance... we are only using this because it will conveniently find the differences //and fire them off for us //enhance: we can skip this and just say "something changed in this entry", //until we really *need* the details (if ever), and have a way to call this then //_mergingStrategy.MakeMergedEntry(this.EventListener, child, parent, parent); EventListener.ChangeOccurred(new XmlChangedRecordReport(_parentFileInRevision, _childFileInRevision, parent, child, url)); } } _processedIds.Add(id); }
public string GetMergedLift() { // string path = Path.Combine(System.Environment.GetEnvironmentVariable("temp"), // @"chorusMergeResult" + Path.GetFileName(_alphaLiftPath) + ".txt"); // // File.WriteAllText(path, "ENter GetMergedLift()"); var ancestorDom = new XmlDocument(); ancestorDom.LoadXml(_ancestorLift); //var comonIdToNodeIndex = new Dictionary<string, XmlNode>(StringComparer.OrdinalIgnoreCase); var alphaDom = new XmlDocument(); alphaDom.LoadXml(_alphaLift); var alphaIdToNodeIndex = new Dictionary <string, XmlNode>(StringComparer.OrdinalIgnoreCase); var betaDom = new XmlDocument(); betaDom.LoadXml(_betaLift); var betaIdToNodeIndex = new Dictionary <string, XmlNode>(StringComparer.OrdinalIgnoreCase); var processedIds = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // The memory stream, rather than a string builder, is needed to avoid utf-16 coming out using (var memoryStream = new MemoryStream()) { //foreach (XmlNode commonNode in _ancestorDom.SafeSelectNodes("lift/entry")) // comonIdToNodeIndex[LiftUtils.GetId(commonNode)] = commonNode; foreach (XmlNode alphaNode in alphaDom.SafeSelectNodes("lift/entry")) { alphaIdToNodeIndex[LiftUtils.GetId(alphaNode)] = alphaNode; } foreach (XmlNode betaNode in betaDom.SafeSelectNodes("lift/entry")) { betaIdToNodeIndex[LiftUtils.GetId(betaNode)] = betaNode; } var settings = CanonicalXmlSettings.CreateXmlWriterSettings(); settings.CloseOutput = false; using (var writer = XmlWriter.Create(memoryStream, settings)) { WriteStartOfLiftElement(writer, alphaDom); ProcessHeaderNodeHACK(writer, alphaDom, betaDom); // Process alpha's entries ProcessEntries(writer, EventListener, _mergingStrategy, ancestorDom, processedIds, alphaDom, "alpha", _alphaLift, betaIdToNodeIndex, "beta", _betaLift); // Process beta's entries ProcessEntries(writer, EventListener, _mergingStrategy, ancestorDom, processedIds, betaDom, "beta", _betaLift, alphaIdToNodeIndex, "alpha", _alphaLift); writer.WriteEndElement(); writer.Close(); } // Don't use GetBuffer()!!! it pads the results with nulls: return Encoding.UTF8.GetString(memoryStream.ToArray()); // This works but doubles the ram use: return Encoding.UTF8.GetString(memoryStream.ToArray()); return(Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Position)); } }
private static void ProcessEntry(XmlWriter writer, IMergeEventListener eventListener, IMergeStrategy mergingStrategy, XmlNode ancestorDom, HashSet <string> processedIds, XmlNode sourceEntry, string sourceLabel, string sourcePath, IDictionary <string, XmlNode> otherIdNodeIndex, string otherLabel, string otherPath) { var id = LiftUtils.GetId(sourceEntry); if (processedIds.Contains(id)) { return; // Already handled the id. } XmlNode otherEntry; var commonEntry = FindEntry(ancestorDom, id); if (!otherIdNodeIndex.TryGetValue(id, out otherEntry)) { // It is in source, but not in target, so it clearly has been deleted by target (new style deletion). if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { if (!LiftUtils.GetIsMarkedAsDeleted(commonEntry)) { // source and target both deleted but in different ways, so make deletion change report. // There is no need to write anything. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, sourceEntry)); } //else //{ // // Make it go away without fanfare by doing nothing to writer, since target actually removed the dead entry. //} processedIds.Add(id); return; } if (commonEntry == null) { // source added it eventListener.ChangeOccurred(new XmlAdditionChangeReport(sourcePath, sourceEntry)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } else { if (AreTheSame(sourceEntry, commonEntry)) { // target's deletion wins with a plain vanilla deletion report. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, otherEntry)); } else { // source wins over target's new style deletion on the least loss priciple. // Add an edit vs remove conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } processedIds.Add(id); return; } } else if (AreTheSame(sourceEntry, otherEntry)) { //unchanged or both made same change writer.WriteNode(sourceEntry.CreateNavigator(), false); } else if (LiftUtils.GetIsMarkedAsDeleted(otherEntry)) { // source edited, target deleted (old style deletion using dateDeleted attr). eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); } else if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { // source deleted (old style), but target edited. // target wins with the least loss principle. // But generate a conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", otherEntry, sourceEntry, commonEntry, new MergeSituation(otherPath, otherLabel, "", sourceLabel, "", MergeOrder.ConflictHandlingModeChoices.TheyWin), null, sourceLabel)); writer.WriteNode(otherEntry.CreateNavigator(), false); } else { // One or both of them edited it, so merge the hard way. using (var reader = XmlReader.Create(new StringReader( mergingStrategy.MakeMergedEntry(eventListener, sourceEntry, otherEntry, commonEntry) ))) { writer.WriteNode(reader, false); } } processedIds.Add(id); }