Aspose - IReplacingCallback - Works for One occurrence and breaks in the second occurence

public class CrossReferenceAddingEvaluator : IReplacingCallback
{
    private readonly string mStartBookmarkNumber;
    private readonly string insertReferenceType;
    private readonly string preText;

    internal CrossReferenceAddingEvaluator(FindReplaceOptions options)
    {
        mStartBookmarkNumber = CrossReferenceController.CorrectedbookmarkStartNumber;
        insertReferenceType = CrossReferenceController.insertReferenceType;
        preText = CrossReferenceController.preText;
    }

    private static Aspose.Words.Run SplitRun(Aspose.Words.Run run, int position)
    {
        Aspose.Words.Run afterRun = (Aspose.Words.Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring(0, 0 + position);
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }

    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs args)
    {

        bool needtoCheckPreText = !String.IsNullOrEmpty(preText);
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = args.MatchNode.Clone(true);
        Node prevNodeVal = currentNode;
        // 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 (args.MatchOffset > 0)
            currentNode = SplitRun((Aspose.Words.Run)currentNode, args.MatchOffset);

        // This array is used to store all nodes of the match for further highlighting.
        ArrayList runs = new ArrayList();

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

            prevNodeVal = currentNode;

            // 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((Aspose.Words.Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        DocumentBuilder oDocBuild = new DocumentBuilder(args.MatchNode.Document as Document);

        // Now Add field codes in the sequence

        if (currentNode != null)
        {
            if (needtoCheckPreText && currentNode.PreviousSibling.GetText().Trim().EndsWith(preText) || !needtoCheckPreText)
            {
                oDocBuild.MoveTo(currentNode);
                SelectInsertReferenceType(oDocBuild);

                foreach (Run run in runs)
                {
                    run.Remove();
                }
            }


        }
        else
        {
            oDocBuild.MoveTo(prevNodeVal);
        }

        return ReplaceAction.Skip;
    }



    private void SelectInsertReferenceType(DocumentBuilder oDocBuild)
    {
        switch (insertReferenceType)
        {
            case "page_number":
                FieldPageRef ReffieldPage = (FieldPageRef)oDocBuild.InsertField(FieldType.FieldPageRef, false);
                ReffieldPage.BookmarkName = "_Ref" + mStartBookmarkNumber;
                ReffieldPage.InsertHyperlink = true;
                ReffieldPage.Update();
                break;
            case "paragraph_number":
            case "paragraph_number_no_context":
            case "paragraph_number_full_context":
            case "above_or_below":
            case "paragraph_text":
                FieldRef Reffield = (FieldRef)oDocBuild.InsertField(FieldType.FieldRef, false);
                Reffield.InsertParagraphNumber = insertReferenceType != "paragraph_text" && insertReferenceType != "above_or_below";
                if (insertReferenceType == "paragraph_number_full_context")
                {
                    Reffield.InsertParagraphNumberInFullContext = true;
                }
                else if (insertReferenceType == "paragraph_number_no_context")
                {
                    Reffield.InsertParagraphNumberInRelativeContext = true;
                }
                if (insertReferenceType == "above_or_below")
                {
                    Reffield.InsertRelativePosition = true;
                }
                Reffield.BookmarkName = "_Ref" + mStartBookmarkNumber;
                Reffield.InsertHyperlink = true;
                Reffield.Update();
                break;
        }
    }
}

I have a paragraph text like this

“For the purposes of this paragraph 8, references to intangible fixed assets mean intangible fixed assets and goodwill within the meaning of Part 8 of Corporation Tax Act 2009.”

My target is replace 8 both in paragraph 8 and Part 8. but replaces only in first occurrence and fails in second.

my search is

doc.Sections[0].Body.GetChildNodes(NodeType.Paragraph, true)[paraIds[i] - 1].Range.Replace(new Regex("\\b(?<!\\.)" + findText + "(?!\\.)\\b"), String.Empty, options);

where findText is “8”

Someone please help on this?

Regards
N. Thiyagarajan

@coderthiyagarajan1980 Please try searching in backward direction:

FindReplaceOptions opt = new FindReplaceOptions(FindReplaceDirection.Backward, callback);

If the problem still persist, please attach your problematic document here for testing. We will check the issue and provide you more information.

@alexey.noskov No, I still have the same issue.before23.zip (62.8 KB)

@alexey.noskov The paragraph I am checking is 419 so you may give

doc.Sections[0].Body.GetChildNodes(NodeType.Paragraph, true)[[418].Range.Replace(new Regex("\\b(?<!\\.)" + findText + "(?!\\.)\\b"), String.Empty, options); 

directly.

@coderthiyagarajan1980 There is a mistake in the IReplacingCallback implementation. In the method IReplacingCallback.Replacing the following line of code:

// This is a Run node that contains either the beginning or the complete match.
Node currentNode = args.MatchNode.Clone(true);

should be

// This is a Run node that contains either the beginning or the complete match.
Node currentNode = args.MatchNode;

Otherwise currentNode is a new node that has no parent and SplitRun method throws when process it.

@alexey.noskov Earlier code was Node currentNode = args.MatchNode; only but that also fails. Hence for testing only, I changed like this.

@alexey.noskov I feel issue is with the split run method. If any one helps me on this, then it will be better help.

@alexey.noskov The condition here is straight forward. Search for text and look pre-text, if matches then replace else skip and go for next match.

@coderthiyagarajan1980 The following test code works for both occurrences:

Document doc = new Document(@"C:\Temp\in.xml");

FindReplaceOptions options = new FindReplaceOptions( FindReplaceDirection.Backward, new CrossReferenceAddingEvaluator());

string findText = "8";
doc.Sections[0].Body.GetChildNodes(NodeType.Paragraph, true)[418].Range.Replace(new Regex("\\b(?<!\\.)" + findText + "(?!\\.)\\b"), String.Empty, options);

what is your test preText and insertReferenceType values?

Expected Replacement.PNG (15.3 KB)
Values for api parameters.PNG (8.3 KB)
api parameters.PNG (4.3 KB)

@alexey.noskov We pass ooxml, replace text and pre-text from MFE to Back end code.

if the pre-text is “paragraph”, then 8 in paragraph 8 should be replaced and hyperlinked.

if the pre-text is “Part”, then 8 in Part 8 should be replaced and hyperlinked.

@alexey.noskov Hopefully, I am near the fix. will let you know once done.

@coderthiyagarajan1980 Unfortunately, I cannot reproduce the problem. I have used the following hardcoded values for testing:

mStartBookmarkNumber = "0";
insertReferenceType = "page_number";
preText = "paragraph";

Also tested with

preText = "Part";

The code works as expected.

Yeah it’s fixed. We can mark it as resolved. It will help others.

1 Like

Thanks @alexey.noskov for your support.

1 Like