We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

Adding Hyperlink to Exisiting word document

I am trying to add a hyperlink to a particular string in an existing word document with Aspose.

Below is the code I tried:

public class ReplaceWithHyperlinkEvaluator implements IReplacingCallback{
public int replace(Object sender, IReplacingCallback e) throws Exception{
** //Get MatchNode**
** Run run1 = (Run)e.getMatchNode();**
** Run run2 = (Run)run1.deepClone(true);**

** //Get index of match value**
** int index = run1.getText().indexOf(e.getMatch().group());**
** //split run that contains matched text**
** run2.setText(run1.getText().substring(index + e.getMatch().group().length()));**
** run1.setText(run1.getText().substring(0, index));**
** run1.getParentParagraph().insertAfter(run2, run1);**
** DocumentBuilder builder = new DocumentBuilder(e.getMatchNode().getDocument());**

** //Move to mathed node**
** builder.moveTo(run2);**
** builder.getFont().setUnderline(Underline.SINGLE);**
** builder.getFont().setColor(Color.BLUE);**

** //Insert hyperlink**
** builder.insertHyperlink(e.getMatch().group(), “D:\test.xlsx”, false);**
** return ReplaceAction.SKIP;**
** }**

** @Override**
** public int replacing(ReplacingArgs ra) throws Exception {**
** throw new UnsupportedOperationException(“Not supported yet.”); **
** }**
}

It is showing an error that getMatchNode() and getMatch() is not in the interface implemented. Earlier I Tried ReplaceEvaluator where the interface itself was not available. Kindly help me out.
Thanks.

@NayanZubeen,

Please ZIP and attach your sample input document and expected Word document here for testing. You can create expected Word document by using MS Word. We will then investigate the issue on our end and provide you more information.

test.zip (15.4 KB)
please find attached the sample input and output docx files.
Here I will give “Nayan345” as input and the hyperlink should be attached to that string only.

Thank you

@NayanZubeen,

Please try using the following code:

static class ReplacingCallbackHandler implements IReplacingCallback {

    public int replacing(ReplacingArgs e) throws Exception {
        Node currentNode = e.getMatchNode();

        // 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.getMatchOffset() > 0)
            currentNode = SplitRun((Run) currentNode, e.getMatchOffset());

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

        // Find all runs that contain parts of the match string.
        int remainingLength = e.getMatch().group(0).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.getNextSibling();
            }
            while ((currentNode != null) && (currentNode.getNodeType() != 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);
        }

        DocumentBuilder builder = new DocumentBuilder((Document) e.getMatchNode().getDocument());
        builder.moveTo((Run) runs.get(0));
        builder.getFont().setStyleIdentifier(StyleIdentifier.HYPERLINK);
        builder.insertHyperlink(e.getMatch().group(0), "https://www.aspose.com/", false);

        //Now remove all runs in the sequence.
        for (Run run : (Iterable<Run>) runs)
            run.remove();

        return ReplaceAction.SKIP;
    }
}

private static Run SplitRun(Run run, int position) throws Exception {
    Run afterRun = (Run) run.deepClone(true);
    afterRun.setText(run.getText().substring(position));
    run.setText(run.getText().substring(0, position));
    run.getParentNode().insertAfter(afterRun, run);
    return afterRun;
}

Document doc = new Document("D:\\temp\\test\\testOutput.docx");

FindReplaceOptions opts = new FindReplaceOptions(FindReplaceDirection.BACKWARD);
opts.setReplacingCallback(new ReplacingCallbackHandler());

doc.getRange().replace("Nayan345", "", opts);

doc.save("D:\\Temp\\test\\awjava-18.6.docx");

Hope, this helps.

Thanks. I’ll check it and reply to you ASAP

Hey, thanks! Output is what I expected but I had to comment the second replace method as my Netbeans ide was showing an error that this method is already defined in the class.

@NayanZubeen,

It is great that you were able to resolve this issue on your end. Please let us know anytime you have any further queries.

Hi Awais,
I have one more query. Does replace returns something on successful search?

doc.getRange().replace(“Nayan345”,"",opts);

I want to know whether the searching was successful or not! So where can I check this?
Is it from the remaining length?

int remainingLength = e.getMatch().group(0).length();

Thanks in advance!

@NayanZubeen,

When replacing(ReplacingArgs args) method is called, it means that Aspose.Words has found a match. Now you can build logic in class to return some flag/values. For example, please check:

Document doc = new Document("D:\\temp\\test\\testOutput.docx");

ReplacingCallbackHandler handler = new ReplacingCallbackHandler();
FindReplaceOptions opts = new FindReplaceOptions(FindReplaceDirection.BACKWARD);
opts.setReplacingCallback(handler);

doc.getRange().replace("Nayan345", "", opts);
System.out.println(handler.isReplaced);

doc.save("D:\\Temp\\test\\awjava-18.6.docx");

static class ReplacingCallbackHandler implements IReplacingCallback {
    public boolean isReplaced;

    public ReplacingCallbackHandler(){
        isReplaced = false;
    }

    public int replacing(ReplacingArgs e) throws Exception {
        Node currentNode = e.getMatchNode();

        // 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.getMatchOffset() > 0)
            currentNode = SplitRun((Run) currentNode, e.getMatchOffset());

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

        // Find all runs that contain parts of the match string.
        int remainingLength = e.getMatch().group(0).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.getNextSibling();
            }
            while ((currentNode != null) && (currentNode.getNodeType() != 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);
        }

        DocumentBuilder builder = new DocumentBuilder((Document) e.getMatchNode().getDocument());
        builder.moveTo((Run) runs.get(0));
        builder.getFont().setStyleIdentifier(StyleIdentifier.HYPERLINK);
        builder.insertHyperlink(e.getMatch().group(0), "https://www.aspose.com/", false);

        isReplaced = true;

        //Now remove all runs in the sequence.
        for (Run run : (Iterable<Run>) runs)
            run.remove();

        return ReplaceAction.SKIP;
    }
}

private static Run SplitRun(Run run, int position) throws Exception {
    Run afterRun = (Run) run.deepClone(true);
    afterRun.setText(run.getText().substring(position));
    run.setText(run.getText().substring(0, position));
    run.getParentNode().insertAfter(afterRun, run);
    return afterRun;
}

Thanks for your valuable time @awais.hafeez
I will implement the logic provided by you.
Might bother you in future again If I come across some problem. Thanks again

@NayanZubeen,

Sure, please let us know anytime you have any further queries.

1 Like

Hi @awais.hafeez. I have noticed some unusual stuff. Size of my output word document with the hyperlinks is less than the size of input word document. But when I open the output document there is absolutely no loss of data. Why is it happening? In case of some bigger word document like containing 300-400 pages, will there be any problems?

@NayanZubeen,

The size of Aspose.Words generated output documents may vary. There should not be a problem. Aspose.Words preserves all document elements during conversions. However, please report the problems if you see some loss of data or any layout/rendering issues in Aspose.Words generated output document. We will then investigate the issue on our end and provide you more information.

1 Like

Okay then. As long as there is no loss of data, it’s fine.

But there is another issue I just come through. I was testing my project in MS word 2007. Other than file size getting reduced, there is no issue till now.
Yesterday I tried it in MS word 2010 and I found that hyperlinking in table is not properly working, precisely the search strings get the hyperlinks successfully but not the blue color. Why is it happening?
Then I tested it in word 2013 and again it is working fine.

@NayanZubeen,

Thanks for your inquiry. Please ZIP and attach the following resources here for testing:

  • Your input Word document
  • Aspose.Words 18.7 generated output document (DOCX file) showing the undesired behavior
  • Please create a standalone console application (source code without compilation errors) that helps us to reproduce your problem on our end and attach it here for testing.

As soon as you get these pieces of information ready, we will start investigation into your issue and provide you more information. Thanks for your cooperation.