1

I am developing a compare tool for the word document, whenever there is difference in both the document i need to highlight the substring in the paragraph.When i try to highlight using run, its highlighting whole paragraph instead of the sub string.

Can you please guide us, how can i achieve this for a substring.

madhusan
  • 21
  • 2
  • 1
    See https://stackoverflow.com/questions/35419619/how-can-i-set-background-colour-of-a-run-a-word-in-line-or-a-paragraph-in-a-do/35508229#35508229 – Axel Richter May 29 '17 at 12:39
  • the link is to create a new document ,i am facing issue to highlight substring for run attribute. – madhusan May 29 '17 at 13:21
  • 1
    The code shows how to highlight a run. You cannot format a part of a run. At first you must create a new run containing only the substring and then you can format that run. – Axel Richter May 29 '17 at 13:32
  • In this [Answer](https://stackoverflow.com/questions/40318507/how-do-i-change-color-of-a-particular-word-document-using-apache-poi/40327308#40327308) I gave an example on how to loop through all runs and format one single character different. This also needs each of this single characters to be in its own run. An this is **simple** because only one single character has to be formatted. Only to give you an idea of how complex your requirement will be. – Axel Richter May 29 '17 at 15:11

1 Answers1

1

I had the same problem. Here I post a sample method where you highlight a substring contained in a run.

private int highlightSubsentence(String sentence, XWPFParagraph p, int i) {
    //get the current run Style - here I might need to save the current style
    XWPFRun currentRun = p.getRuns().get(i);
    String currentRunText = currentRun.text();
    int sentenceLength = sentence.length();
    int sentenceBeginIndex = currentRunText.indexOf(sentence);
    int addedRuns = 0;
    p.removeRun(i);
    //Create, if necessary, a run before the highlight part
    if (sentenceBeginIndex > 0) {
        XWPFRun before = p.insertNewRun(i);
        before.setText(currentRunText.substring(0, sentenceBeginIndex));
        //here I might need to re-introduce the style of the deleted run
        addedRuns++;
    }

    // highlight the interesting part
    XWPFRun sentenceRun = p.insertNewRun(i + addedRuns);
    sentenceRun.setText(currentRunText.substring(sentenceBeginIndex, sentenceBeginIndex + sentenceLength));
    currentStyle.copyStyle(sentenceRun);
    CTShd cTShd = sentenceRun.getCTR().addNewRPr().addNewShd();
    cTShd.setFill("00FFFF");

    //Create, if necessary, a run after the highlight part
    if (sentenceBeginIndex + sentenceLength != currentRunText.length()) {
        XWPFRun after = p.insertNewRun(i + addedRuns + 1);
        after.setText(currentRunText.substring(sentenceBeginIndex + sentenceLength));
        //here I might need to re-introduce the style of the deleted run
        addedRuns++;
    }
    return addedRuns;
}

You might need to save the formatting style of the run you delete in order to have the new runs with the old formatting.

Also, if the string you need to highlight is spread over more than one run, you will need to highlight all of them, but the core method is the one I posted.

On the Style Question: I had a class Style that saved all the Styles of the old Run in private fields (for the respective classes you can look at what XWPFRun returns. These are the sub-styles that I needed. There are others obviously I didn't cover

Style(XWPFRun run, XWPFDefaultRunStyle defaultRunStyle) {
    fontSize = run.getFontSize();
    fontFamily = run.getFontFamily();
    bold = run.isBold();
    italic = run.isItalic();
    strike = run.isStrikeThrough();
    underline = run.getUnderline();
    color = run.getColor();
    shadingColor = getShadeColor(run);
    highlightColor = getHighlightedColor(run);
}

I copied the old style in the new run when needed.

public void copyStyle(XWPFRun newRun) {
    if (fontSize != -1) {
        newRun.setFontSize(fontSize);
    }
    newRun.setFontFamily(fontFamily);
    newRun.setBold(bold);
    newRun.setItalic(italic);
    newRun.setStrikeThrough(strike);
    newRun.setColor(color);
    newRun.setUnderline(underline);
    if (shadingColor != null) {
        addShading(newRun, shadingColor);
    }
    if (highlightColor != null) {
        addHighlight(newRun, highlightColor);
    }
}

To add Shading and Highligh already present I used:

public static void addHighlight(XWPFRun run, STHighlightColor.Enum hexColor) {
    if (run.getCTR().getRPr() == null) {
        run.getCTR().addNewRPr();
    }
    if (run.getCTR().getRPr().getHighlight() == null) {
        run.getCTR().getRPr().addNewHighlight();
    }
    run.getCTR().getRPr().getHighlight().setVal(hexColor);
}

public static void addShading(XWPFRun run, Object hexColor) {
    if (run.getCTR().getRPr() == null) {
        run.getCTR().addNewRPr();
    }
    if (run.getCTR().getRPr().getShd() == null) {
        run.getCTR().getRPr().addNewShd();
    }
    run.getCTR().getRPr().getShd().setFill(hexColor);
}
Ale
  • 946
  • 4
  • 17
  • 28