Skip to content

BUG: Shape with empty paragraph & textrun generates invalid XML #919

@sascha08-15

Description

@sascha08-15

POI creates invalid pptx files if we call .clearText and do not create a paragraph and textrun in it. The later is the workaround; however, this IS a bug.

Test to reproduce below, just open the created file in PowerPoint (on Mac) it will complain about invalid xml.

import org.apache.poi.sl.usermodel.ShapeType;
import org.junit.jupiter.api.Test;

import java.awt.geom.Rectangle2D;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.*;

public class PoiClearTextPptxTest {

    @Test
    public void createShapeClearTextAndSave_pptxShouldBeReportedInvalidByPowerPoint() throws Exception {
        // create a new presentation
        try (XMLSlideShow ppt = new XMLSlideShow()) {
            // create a slide
            XSLFSlide slide = ppt.createSlide();

            // create a rectangle auto-shape and position it
            XSLFAutoShape rect = slide.createAutoShape();
            rect.setShapeType(ShapeType.RECT);
            rect.setAnchor(new Rectangle2D.Double(100, 100, 400, 120));

            // add text to the shape
            XSLFTextParagraph p = rect.addNewTextParagraph();
            XSLFTextRun run = p.addNewTextRun();
            run.setText("This is a test text that will be cleared.");

            // sanity-check text is present
            assertTrue(rect.getText().contains("This is a test text"));

            // THIS IS THE KEY CALL: remove all text content from the shape
            rect.clearText();

            // After clearText(), POI leaves the shape without text runs/paragraphs in its model.
            // That can produce a PPTX that PowerPoint flags as "needs repair" / invalid.

            // write to a temporary file
            Path out = Files.createTempFile("poi-cleartext-repro-", ".pptx");
            try (FileOutputStream fos = new FileOutputStream(out.toFile())) {
                ppt.write(fos);
            }

            // Basic checks
            assertTrue(Files.exists(out));
            assertTrue(Files.size(out) > 0);

            System.out.println("Wrote test file to: " + out.toAbsolutePath());

            // Optional: try to re-open with POI (may succeed even if PowerPoint complains)
            try (FileInputStream fis = new FileInputStream(out.toFile());
                 XMLSlideShow reopened = new XMLSlideShow(fis)) {
                // inspect shapes for missing text bodies
                boolean foundTextShape = false;
                for (XSLFShape s : reopened.getSlides().get(0).getShapes()) {
                    if (s instanceof XSLFTextShape) {
                        foundTextShape = true;
                        XSLFTextShape ts = (XSLFTextShape) s;
                        // after clearText(), paragraphs/runs often are empty
                        System.out.println("Reopened shape text (may be empty): '" + ts.getText() + "'");
                    }
                }
                assertTrue(foundTextShape, "We expected at least one text shape on the slide");
            }

            // Note: open the printed file path in MS PowerPoint to reproduce the "invalid" report.
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions