Aspose compare output with bookmarks is not matching compare output from Word

Hello Support,

I was trying to compare documents with bookmarks and I am finding it different from compare output of word and even with compare output of aspose itself when instead of tables there are rows.

Please see attached zip file CompareBookmarkIssue.zip (26.9 KB)
with two files and compare output from Word and Aspose. In Aspose output there are only 33 bookmarks where as as per word output 41 bookmarks are needed. Output with 41 bookmarks is correct.

Code used

Document docOrg = new Document("D:\\Aspose\\Test1_OLD.docx");
Document doc=new Document("D:\\Aspose\\Test1.docx");
Aspose.Words.CompareOptions options=new CompareOptions();
options.IgnoreFormatting=false;
options.IgnoreHeadersAndFooters=true;
docOrg.LayoutOptions.RevisionOptions.ShowRevisionBalloons=false;
docOrg.LayoutOptions.RevisionOptions.InsertedTextColor = Aspose.Words.Layout.RevisionColor.Blue;
docOrg.LayoutOptions.RevisionOptions.DeletedTextColor = Aspose.Words.Layout.RevisionColor.Red;
docOrg.Compare(doc,"System",DateTime.Now,options);
docOrg.Save("D:\\Aspose\\TestCompare_Aspose.docx",SaveFormat.Docx);

Please suggest what modifications are required to resolve issue so that word compare and aspose compare will match.

Thanks in advance.
Mandar

@mandar_limaye,

Thanks for your inquiry. We have tested the scenario and have managed to reproduce the same issue at our side. For the sake of correction, we have logged this problem in our issue tracking system as WORDSNET-16405. You will be notified via this forum thread once this issue is resolved.

We apologize for your inconvenience.

Hello Tahir,
I am working on woraround to resolve this issue, my approach is replacebookmarks with the text with name of bookmarks in both document and then after compare again replace text with bookmarks. During first run bookmark name will be collected and after compare matching that text will be replaced by bookmark with same name,
In this approach if possible looking for code snippet to first insert text for bookmarks with their name and then replace text with bookmarks with name as text.

Your support is highly appreciated.

Thanks in advance.

Regards
Mandar

@mandar_limaye,

Thanks for your inquiry. Unfortunately, there is no workaround available for this issue. Once our product team completes the analysis of this issue, we will then provide you the update on this issue. Thanks for your patience.

Hello Tahir,

Is it possible to share a code to replace bookmarks with text in word document?

Thanks
Mandar

@mandar_limaye,

Thanks for your inquiry. Please refer to the following articles.
Use DocumentBuilder to Insert Document Elements
Moving to a Bookmark

Please use the following code example to insert the text in bookmark. Hope this helps you.

Document doc = new Document(MyDir + "in.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToBookmark("bookmarkname", false, false);
builder.Write("Text after bookmark");

doc.Save(MyDir + "18.1.docx");

Hello Tahir,

Thanks for pointing and I suppose in same way I could insert bookmark at specific text.

So here what I am planning to do

  1. In both documents insert text with bookmarks name
  2. Compare documents ( Text is coming properly)
  3. After compare again replace text with bookmark with name as text

I expect that this workaround will work for now.

Regards
Mandar

@mandar_limaye,

Thanks for your inquiry. You can use this workaround for only adding bookmarks for this case. However, this will not work for document comparison.

In this case, we suggest you following solution.

  1. Please iterate through all bookmarks of test1.docx
  2. Check if the bookmark exists in final output document e.g. its name is output.docx
  3. If bookmark does not exist, get the text after the bookmark from test1.docx. You can get the text using Run.Text property.
  4. Find this text using Range.Replace method in output.docx and insert the bookmark before the text.
  5. You need to implement IReplacingCallback interface to find the text and insert the bookmark. Please refer to the following article.
    Find and Replace

Following class implements IReplacingCallback. You can use this class to find the text and insert bookmark before text.

public class FindInsertBookmark : IReplacingCallback
{
    string bmname;
    DocumentBuilder builder;
    public FindInsertBookmark(string bmname)
    {
        this.bmname = bmname;
    }
    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;

        if (builder == null)
            builder = new DocumentBuilder((Document)currentNode.Document);

        // The first (and may be the only) run can contain text before the match, 
        // in this case it is necessary to split the run.
        if (e.MatchOffset > 0)
            currentNode = SplitRun((Run)currentNode, e.MatchOffset);

        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;
        while (
            (remainingLength > 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;

            // Select the next Run node. 
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do
            {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }

        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength > 0))
        {
            SplitRun((Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        Run run = (Run)runs[0];
        builder.MoveTo(run);
        builder.StartBookmark(this.bmname);
        builder.EndBookmark(this.bmname);
        // Signal to the replace engine to do nothing because we have already done all what we wanted.
        return ReplaceAction.Skip;
    }

    /// <summary>
    /// Splits text of the specified run into two runs.
    /// Inserts the new run just after the specified run.
    /// </summary>
    private static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring(0, position);
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}

How to us the above class:

FindReplaceOptions options = new FindReplaceOptions();
options.ReplacingCallback = new FindInsertBookmark("bookmark name...");

doc.Range.Replace("The System shall allow user to manage Rentals", "", options);

The issues you have found earlier (filed as WORDSNET-16405) have been fixed in this Aspose.Words for .NET 22.12 update also available on NuGet.