Search code examples
javaapache-poipowerpoint

Replace a word in a XSLFTextRun with Apache POI


I am using Apache POI to modify a pptx. I am trying to replace one word in a XSLFTextShape while keeping the formatting of the other words in the XSLFTextShape .

What I tried so far is the following:

private static void replaceText(XSLFTextShape textShape, String marker, String newText){
        textShape.setText(textShape.getText().replace(marker, newText));
    }

This is replacing the word I want, but the formatting of the other words in the same XSLFTextShape is changed. For example: If I have a word in the same XSLFTextShape which is red, the color of this word is changed to black even though I am not changing anything in this word.

Therefore I tried to replace the word in the XSLFTextRun. This is the code I wrote:

    private static void replaceText(XSLFTextShape textShape, String marker, String newText){

        List<XSLFTextParagraph> textParagraphList = textShape.getTextParagraphs();
        textParagraphList.forEach(textParagraph -> {
            List<XSLFTextRun> textRunList = textParagraph.getTextRuns();
            textRunList.forEach(textRun -> {
                if(textRun.getRawText().contains(marker)){
                    textRun.setText(textRun.getRawText().replace(marker, newText));
                }
            });
        });
        //String text = textShape.getText();
        //textShape.setText(textShape.getText().replace(marker, newText));
        //String text2 = textShape.getText();
    }

I am not getting any error when running this code, but the word is not replaced and I really don't get why. If I add the line textShape.setText(textShape.getText().replace(marker, newText)); it is replaced. But while debugging, I see that textShape.getText()gives the same result before and after this line.

Thanks for your help!


Solution

  • Ok, so I made it work somehow with a (not very nice) workaround: I am saving the text and style per paragraph, delete the text in the shape and then add new paragraphs with the textruns (including style). Here is the code:

    private static void replaceTextButKeepStyle(XSLFTextShape textShape, final String marker, final String text) {
        List<XSLFTextParagraph> textParagraphList = textShape.getTextParagraphs();
        ArrayList<ArrayList<TextAndStyle>> textAndStylesTable = new ArrayList<>();
    
        for (int i = 0; i < textParagraphList.size(); i++) {
            ArrayList<TextAndStyle> textAndStylesParagraph = new ArrayList<>();
    
            XSLFTextParagraph textParagraph = textParagraphList.get(i);
    
            List<XSLFTextRun> textRunList = textParagraph.getTextRuns();
    
            for (Iterator it2 = textRunList.iterator(); it2.hasNext(); ) {
                Object object = it2.next();
                XSLFTextRun textRun = (XSLFTextRun) object;
    
                //get Color:
                PaintStyle.SolidPaint solidPaint = (PaintStyle.SolidPaint) textRun.getFontColor(); 
                int color = solidPaint.getSolidColor().getColor().getRGB();
    
                //save text & styles:
                TextAndStyle textAndStyle = new TextAndStyle(textRun.getRawText(), textRun.isBold(),
                        color, textRun.getFontSize());
    
                //replace text if marker:
                if (textAndStyle.getText().contains(marker)) {
                    textAndStyle.setText(textAndStyle.getText().replace(marker, text));
                }
    
                textAndStylesParagraph.add(textAndStyle);
            }
            textAndStylesTable.add(textAndStylesParagraph);
        }
    
        //delete text and add new text with correct styles:
        textShape.clearText();
        textAndStylesTable.forEach(textAndStyles -> {
            XSLFTextParagraph textParagraph = textShape.addNewTextParagraph();
            textAndStyles.forEach(textAndStyle -> {
                TextRun newTextrun = textParagraph.addNewTextRun();
                newTextrun.setText(textAndStyle.getText());
                newTextrun.setFontColor(new Color(textAndStyle.getColorRgb()));
                newTextrun.setBold(textAndStyle.isBold());
                newTextrun.setFontSize(textAndStyle.getFontsize());
            });
        });
    }