Update to CommentMerger.MergeComments Method

Word 2007 has a feature where you can lock a document, preventing any changes to content, yet allowing the user to add comments.  CommentMerger is a small method (~400 lines of code) that merges comments from two documents into a single document, provided the two contain the same content.  This code is part of the PowerTools for Open XML project.  In the future, I'm going to write a cmdlet that will use this code to merge comments.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCI’ve updated the CommentMerger class (actually completely rewritten it).  The new code (again, written in a functional style) is much more robust.  It now merges comments on math formulas.  The code (and example program to use it) is available in the ‘downloads’ tab at codeplex.com/powertools.

There have been two good side effects of this effort – I’ve learned more about the Open XML formats, and I’ve refined my approach for doing recursive pure functional transforms.

One of the biggest differences in the code is the approach that I took to selecting elements for transform.  Previously, I was looking for paragraph nodes, then recursively processing the descendants.  But this became more complicated in certain scenarios – paragraphs can contain runs which contain other content which can contain paragraphs.  In the new version, I simply select the elements for transform based on their contents.  For example, the following code selects a node for transform based on if the node contains any child w:commentRangeStart, w:commentRangeEnd, or runs (w:r) that contain w:commentReference elements:

// If fromElement contains comments, then do special clone that merges comments.
if (fromElement
.Elements()
.Where(e => e.Name == W.commentRangeStart ||
e.Name == W.commentRangeEnd ||
((e.Name == W.r || e.Name == M.r) &&
e.Elements(W.commentReference).Any()
))
.Any())
{
// Get new, cloned element with merged comments.
XElement newToElement = CloneElementWithComments(toElement, fromElement,
commentIdTransformDictionary);
return newToElement;
}

I used this approach throughout the transform.  I had a question about whether this approach would perform well enough.  I believe it does for two reasons – first, the Any extension method ‘short-circuits’ any positive matches, reducing the work to be done.  Second, I think that CPU caching may be effective in these situations.  In any case, the code seems to be more than fast enough.