Search code examples
javaapache-poipowerpoint

How to read text in XSLFGraphicFrame with Apache POI for PowerPoint


I'm making a Java program to find occurrrences of a particular keyword in documents. I want to read many types of file format, including all Microsoft Office documents.

I already made it with all of them except for PowerPoint ones, I'm using Apache POI code snippets found on StackOverflow or on other sources. I discovered all slides are made of shapes (XSLFTextShape) but many of them are objects of class XSLFGraphicFrame or XSLFTable for which I can't use simply the toString() methods. How can I extract all of the text contained in them using Java. This is the piece of code\pseudocode:

File f = new File("C:\\Users\\Windows\\Desktop\\Modulo 9.pptx");
PrintStream out = System.out;

FileInputStream is = new FileInputStream(f);
XMLSlideShow ppt = new XMLSlideShow(is);
for (XSLFSlide slide : ppt.getSlides()) {
    for (XSLFShape shape : slide) {
       if (shape instanceof XSLFTextShape) {
       XSLFTextShape txShape = (XSLFTextShape) shape;
       out.println(txShape.getText());
       } else if (shape instanceof XSLFPictureShape) {
        //do nothing
       } else if (shape instanceof XSLFGraphicFrame or XSLFTable ) {
       //print all text in it or in its children
       }
    }
}

Solution

  • If your requirement "to find occurrences of a particular keyword in documents" needs simply searching in all text content of SlideShows, then simply using SlideShowExtractor could be an approach. This also can act as entry point to an POITextExtractor for getting textual content of the document metadata / properties, such as author and title.

    Example:

    import java.io.FileInputStream;
    
    import org.apache.poi.xslf.usermodel.*;
    import org.apache.poi.sl.usermodel.SlideShow;
    import org.apache.poi.sl.extractor.SlideShowExtractor;
    
    import org.apache.poi.extractor.POITextExtractor;
    
    public class SlideShowExtractorExample {
    
     public static void main(String[] args) throws Exception {
    
      SlideShow<XSLFShape,XSLFTextParagraph> slideshow 
       = new XMLSlideShow(new FileInputStream("Performance_Out.pptx"));
    
      SlideShowExtractor<XSLFShape,XSLFTextParagraph> slideShowExtractor 
       = new SlideShowExtractor<XSLFShape,XSLFTextParagraph>(slideshow);
      slideShowExtractor.setCommentsByDefault(true);
      slideShowExtractor.setMasterByDefault(true);
      slideShowExtractor.setNotesByDefault(true);
    
      String allTextContentInSlideShow = slideShowExtractor.getText();
    
    System.out.println(allTextContentInSlideShow);
    
    System.out.println("===========================================================================");
    
      POITextExtractor textExtractor = slideShowExtractor.getMetadataTextExtractor();
      String metaData = textExtractor.getText();
    
    System.out.println(metaData);
    
     }
    }
    

    Of course there are kinds of XSLFGraphicFrame which are not read by SlideShowExtractor because they are not supported by apache poi until now. For example all kinds of SmartArt graphic. The text content of those is stored in /ppt/diagrams/data*.xml document parts which are referenced from the slides. Since apache poi does not supporting this until now, it only can be read using low level underlying methods.

    For example to additionally get all text out of all /ppt/diagrams/data which are texts in SmartArt graphics we could do:

    ...
    System.out.println("===========================================================================");
    
    //additionally get all text out of all /ppt/diagrams/data which are texts in SmartArt graphics:
      StringBuilder sb = new StringBuilder();
      for (XSLFSlide slide : ((XMLSlideShow)slideshow).getSlides()) {
       for (org.apache.poi.ooxml.POIXMLDocumentPart part : slide.getRelations()) {
        if (part.getPackagePart().getPartName().getName().startsWith("/ppt/diagrams/data")) {
         org.apache.xmlbeans.XmlObject xmlObject = org.apache.xmlbeans.XmlObject.Factory.parse(part.getPackagePart().getInputStream());
         org.apache.xmlbeans.XmlCursor cursor = xmlObject.newCursor();
         while(cursor.hasNextToken()) {
          if (cursor.isText()) {
           sb.append(cursor.getTextValue() + "\r\n");
          }
          cursor.toNextToken();
         }
         sb.append(slide.getSlideNumber() + "\r\n\r\n");
        }
       }
      }
      String allTextContentInDiagrams = sb.toString();
    
    System.out.println(allTextContentInDiagrams);
    ...