You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ta...@apache.org on 2018/10/11 17:44:40 UTC

[tika] 03/03: TIKA-2735 -- allow user to avoid extracting "master" sections and notes sections from ppt[xm]?

This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch branch_1x
in repository https://gitbox.apache.org/repos/asf/tika.git

commit 307a8bd592d6e25419bbad19aac47cc7de201c4d
Author: TALLISON <ta...@apache.org>
AuthorDate: Thu Oct 4 13:32:37 2018 -0400

    TIKA-2735 -- allow user to avoid extracting "master" sections and notes sections from ppt[xm]?
---
 .../tika/parser/microsoft/HSLFExtractor.java       | 268 ++++++++++++---------
 .../tika/parser/microsoft/OfficeParserConfig.java  |  42 +++-
 .../ooxml/SXSLFPowerPointExtractorDecorator.java   |  71 +++---
 .../ooxml/XSLFPowerPointExtractorDecorator.java    |  50 ++--
 .../parser/microsoft/PowerPointParserTest.java     |  48 ++++
 .../parser/microsoft/ooxml/OOXMLParserTest.java    |  43 ++++
 .../parser/microsoft/ooxml/SXSLFExtractorTest.java |  35 +++
 7 files changed, 384 insertions(+), 173 deletions(-)

diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/HSLFExtractor.java b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/HSLFExtractor.java
index 5095709..356c47e 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/HSLFExtractor.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/HSLFExtractor.java
@@ -16,12 +16,6 @@
  */
 package org.apache.tika.parser.microsoft;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
 import org.apache.poi.common.usermodel.Hyperlink;
 import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
 import org.apache.poi.hslf.model.HeadersFooters;
@@ -40,16 +34,17 @@ import org.apache.poi.hslf.usermodel.HSLFSlide;
 import org.apache.poi.hslf.usermodel.HSLFSlideShow;
 import org.apache.poi.hslf.usermodel.HSLFTable;
 import org.apache.poi.hslf.usermodel.HSLFTableCell;
-import org.apache.poi.hslf.usermodel.HSLFTextBox;
 import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
 import org.apache.poi.hslf.usermodel.HSLFTextRun;
 import org.apache.poi.hslf.usermodel.HSLFTextShape;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.sl.usermodel.Comment;
+import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.SimpleShape;
-import org.apache.tika.exception.TikaException;
+import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.tika.exception.EncryptedDocumentException;
+import org.apache.tika.exception.TikaException;
 import org.apache.tika.extractor.EmbeddedDocumentUtil;
 import org.apache.tika.io.CloseShieldInputStream;
 import org.apache.tika.io.IOExceptionWithCause;
@@ -61,6 +56,11 @@ import org.apache.tika.sax.XHTMLContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
 public class HSLFExtractor extends AbstractPOIFSExtractor {
 
     public HSLFExtractor(ParseContext context, Metadata metadata) {
@@ -92,143 +92,169 @@ public class HSLFExtractor extends AbstractPOIFSExtractor {
       /* Iterate over slides and extract text */
         for (HSLFSlide slide : _slides) {
             xhtml.startElement("div", "class", "slide");
+            HeadersFooters slideHeaderFooters =
+                    (officeParserConfig.getIncludeHeadersAndFooters()) ?
+                            slide.getHeadersFooters() : null;
 
-            // Slide header, if present
-            HeadersFooters hf = slide.getHeadersFooters();
-            if (hf != null && hf.isHeaderVisible() && hf.getHeaderText() != null) {
-                xhtml.startElement("p", "class", "slide-header");
+            HeadersFooters notesHeadersFooters =
+                    (officeParserConfig.getIncludeHeadersAndFooters()) ?
+                            ss.getNotesHeadersFooters() : null;
 
-                xhtml.characters(hf.getHeaderText());
+            if (officeParserConfig.getIncludeHeadersAndFooters()) {
+                // Slide header, if present
+                if (slideHeaderFooters != null && slideHeaderFooters.isHeaderVisible() && slideHeaderFooters.getHeaderText() != null) {
+                    xhtml.startElement("p", "class", "slide-header");
 
-                xhtml.endElement("p");
+                    xhtml.characters(slideHeaderFooters.getHeaderText());
+
+                    xhtml.endElement("p");
+                }
             }
 
             // Slide master, if present
-            extractMaster(xhtml, slide.getMasterSheet());
-
-            // Slide text
-            {
-                xhtml.startElement("div", "class", "slide-content");
-
-                textRunsToText(xhtml, slide.getTextParagraphs());
-
-                xhtml.endElement("div");
+            if (officeParserConfig.getIncludeSlideMasterContent()) {
+                extractMaster(xhtml, slide.getMasterSheet());
             }
+            // Slide text
+            xhtml.startElement("div", "class", "slide-content");
+            textRunsToText(xhtml, slide.getTextParagraphs());
 
             // Table text
-            for (HSLFShape shape : slide.getShapes()) {
-                if (shape instanceof HSLFTable) {
-                    extractTableText(xhtml, (HSLFTable) shape);
+            List<HSLFShape> shapes = getShapes(slide);
+            if (shapes != null) {
+                for (HSLFShape shape : shapes) {
+                    if (shape instanceof HSLFTable) {
+                        extractTableText(xhtml, (HSLFTable) shape);
+                    }
                 }
             }
+            extractGroupText(xhtml, slide, 0);
+            //end slide content
+            xhtml.endElement("div");
 
-            extractGroupText(xhtml, slide.getShapes(), 0);
-
-            // Slide footer, if present
-            if (hf != null && hf.isFooterVisible() && hf.getFooterText() != null) {
-                xhtml.startElement("p", "class", "slide-footer");
-
-                xhtml.characters(hf.getFooterText());
-
-                xhtml.endElement("p");
-            }
-
-            // Comments, if present
-            StringBuilder authorStringBuilder = new StringBuilder();
-            for (Comment comment : slide.getComments()) {
-                authorStringBuilder.setLength(0);
-                xhtml.startElement("p", "class", "slide-comment");
-
-                if (comment.getAuthor() != null) {
-                    authorStringBuilder.append(comment.getAuthor());
+            if (officeParserConfig.getIncludeHeadersAndFooters()) {
+                // Slide footer, if present
+                if (slideHeaderFooters != null && slideHeaderFooters.isFooterVisible() && slideHeaderFooters.getFooterText() != null) {
+                    xhtml.startElement("p", "class", "slide-footer");
+                    xhtml.characters(slideHeaderFooters.getFooterText());
+                    xhtml.endElement("p");
                 }
-                if (comment.getAuthorInitials() != null) {
-                    if (authorStringBuilder.length() > 0) {
-                        authorStringBuilder.append(" ");
-                    }
-                    authorStringBuilder.append("("+comment.getAuthorInitials()+")");
-                }
-                if (authorStringBuilder.length() > 0) {
-                    if (comment.getText() != null) {
-                        authorStringBuilder.append(" - ");
-                    }
-                    xhtml.startElement("b");
-                    xhtml.characters(authorStringBuilder.toString());
-                    xhtml.endElement("b");
-                }
-                if (comment.getText() != null) {
-                    xhtml.characters(comment.getText());
-                }
-                xhtml.endElement("p");
             }
+            handleComments(slide, xhtml);
+            handleNotes(slide, notesHeadersFooters, xhtml);
 
             // Now any embedded resources
             handleSlideEmbeddedResources(slide, xhtml);
 
-           
-            // Find the Notes for this slide and extract inline
-            HSLFNotes notes = slide.getNotes();
-            if (notes != null) {
-                xhtml.startElement("div", "class", "slide-notes");
-
-                textRunsToText(xhtml, notes.getTextParagraphs());
-       
-                xhtml.endElement("div");
-            }
-            
-
             // Slide complete
             xhtml.endElement("div");
         }
 
+        handleSlideEmbeddedPictures(ss, xhtml);
+        if (officeParserConfig.getExtractMacros()) {
+            extractMacros(ss, xhtml);
+        }
         // All slides done
         xhtml.endElement("div");
+    }
+
+    private void handleComments(HSLFSlide slide, XHTMLContentHandler xhtml) throws SAXException {
+        if (slide.getComments() == null || slide.getComments().size() == 0) {
+            return;
+        }
+        xhtml.startElement("div", "class", "slide-comments");
 
-      /* notes */
-        xhtml.startElement("div", "class", "slide-notes");
-        HashSet<Integer> seenNotes = new HashSet<>();
-        HeadersFooters hf = ss.getNotesHeadersFooters();
+        // Comments, if present
+        StringBuilder authorStringBuilder = new StringBuilder();
+        for (Comment comment : slide.getComments()) {
+            authorStringBuilder.setLength(0);
+            xhtml.startElement("p", "class", "slide-comment");
 
-        for (HSLFSlide slide : _slides) {
-            HSLFNotes notes = slide.getNotes();
-            if (notes == null) {
-                continue;
+            if (comment.getAuthor() != null) {
+                authorStringBuilder.append(comment.getAuthor());
             }
-            Integer id = notes._getSheetNumber();
-            if (seenNotes.contains(id)) {
-                continue;
+            if (comment.getAuthorInitials() != null) {
+                if (authorStringBuilder.length() > 0) {
+                    authorStringBuilder.append(" ");
+                }
+                authorStringBuilder.append("(" + comment.getAuthorInitials() + ")");
             }
-            seenNotes.add(id);
-
-            // Repeat the Notes header, if set
-            if (hf != null && hf.isHeaderVisible() && hf.getHeaderText() != null) {
-                xhtml.startElement("p", "class", "slide-note-header");
-                xhtml.characters(hf.getHeaderText());
-                xhtml.endElement("p");
+            if (authorStringBuilder.length() > 0) {
+                if (comment.getText() != null) {
+                    authorStringBuilder.append(" - ");
+                }
+                xhtml.startElement("b");
+                xhtml.characters(authorStringBuilder.toString());
+                xhtml.endElement("b");
             }
+            if (comment.getText() != null) {
+                xhtml.characters(comment.getText());
+            }
+            xhtml.endElement("p");
+        }
+        //end comments
+        xhtml.endElement("div");
+    }
+
+    private void handleNotes(HSLFSlide slide,
+                             HeadersFooters notesHeaderFooters, XHTMLContentHandler xhtml) throws SAXException, TikaException, IOException {
 
-            // Notes text
-            textRunsToText(xhtml, notes.getTextParagraphs());
+        if (!officeParserConfig.getIncludeSlideNotes()) {
+            return;
+        }
+        // Find the Notes for this slide and extract inline
+        HSLFNotes notes = slide.getNotes();
+        if (notes == null) {
+            return;
+        }
 
-            // Repeat the notes footer, if set
-            if (hf != null && hf.isFooterVisible() && hf.getFooterText() != null) {
-                xhtml.startElement("p", "class", "slide-note-footer");
-                xhtml.characters(hf.getFooterText());
-                xhtml.endElement("p");
+        xhtml.startElement("div", "class", "notes");
+
+        // Repeat the Notes header, if set
+        if (officeParserConfig.getIncludeHeadersAndFooters() &&
+                notesHeaderFooters != null &&
+                notesHeaderFooters.isHeaderVisible() &&
+                notesHeaderFooters.getHeaderText() != null) {
+            xhtml.startElement("p", "class", "slide-note-header");
+            xhtml.characters(notesHeaderFooters.getHeaderText());
+            xhtml.endElement("p");
+        }
+        xhtml.startElement("div", "class", "notes-content");
+        // Notes text
+        textRunsToText(xhtml, notes.getTextParagraphs());
+
+        List<HSLFShape> shapes = getShapes(notes);
+        if (shapes != null && shapes.size() > 0) {
+            // Table text
+            for (HSLFShape shape : shapes) {
+                if (shape instanceof HSLFTable) {
+                    extractTableText(xhtml, (HSLFTable) shape);
+                }
             }
         }
+        extractGroupText(xhtml, notes, 0);
+        //notes content
+        xhtml.endElement("div");
 
-        handleSlideEmbeddedPictures(ss, xhtml);
-        if (officeParserConfig.getExtractMacros()) {
-            extractMacros(ss, xhtml);
+        // Repeat the Notes footer, if set
+        if (officeParserConfig.getIncludeHeadersAndFooters() &&
+                notesHeaderFooters != null &&
+                notesHeaderFooters.isFooterVisible() &&
+                notesHeaderFooters.getFooterText() != null) {
+            xhtml.startElement("p", "class", "slide-note-footer");
+            xhtml.characters(notesHeaderFooters.getFooterText());
+            xhtml.endElement("p");
         }
+        // Now any embedded resources
+        handleSlideEmbeddedResources(notes, xhtml);
+        //end notes
         xhtml.endElement("div");
     }
 
     //Extract any text that's within an HSLFTextShape that's a descendant of
     //an HSLFGroupShape.
-    private void extractGroupText(XHTMLContentHandler xhtml, List<HSLFShape> shapes, int depth) throws SAXException {
-
+    private void extractGroupText(XHTMLContentHandler xhtml, ShapeContainer shapeContainer, int depth) throws SAXException {
+        List<HSLFShape> shapes = getShapes(shapeContainer);
         if (shapes == null) {
             return;
         }
@@ -239,11 +265,13 @@ public class HSLFExtractor extends AbstractPOIFSExtractor {
         //However, cells are considered grouped within the table, so ignore them.
         //I don't believe that cells can be inside a text box or other
         //grouped text containing object, so always ignore them.
+        //I also don't believe that a table can be grouped with a table.
+        //If these beliefs are wrong...must fix!
         List<List<HSLFTextParagraph>> paragraphList = new ArrayList<>();
         for (HSLFShape shape : shapes) {
             if (shape instanceof HSLFGroupShape) {
                 //work recursively, HSLFGroupShape can contain HSLFGroupShape
-                extractGroupText(xhtml, ((HSLFGroupShape)shape).getShapes(), depth+1);
+                extractGroupText(xhtml, ((HSLFGroupShape)shape), depth+1);
             } else if (shape instanceof HSLFTextShape
                     && ! (shape instanceof HSLFTableCell) && depth > 0) {
                 paragraphList.add(((HSLFTextShape)shape).getTextParagraphs());
@@ -289,7 +317,7 @@ public class HSLFExtractor extends AbstractPOIFSExtractor {
         if (master == null) {
             return;
         }
-        List<HSLFShape> shapes = master.getShapes();
+        List<HSLFShape> shapes = getShapes(master);
         if (shapes == null || shapes.isEmpty()) {
             return;
         }
@@ -441,19 +469,14 @@ public class HSLFExtractor extends AbstractPOIFSExtractor {
         }
     }
 
-    private void handleSlideEmbeddedResources(HSLFSlide slide, XHTMLContentHandler xhtml)
+    private void handleSlideEmbeddedResources(ShapeContainer shapeContainer, XHTMLContentHandler xhtml)
             throws TikaException, SAXException, IOException {
-        List<HSLFShape> shapes;
-        try {
-            shapes = slide.getShapes();
-        } catch (NullPointerException e) {
-            // Sometimes HSLF hits problems
-            // Please open POI bugs for any you come across!
-            EmbeddedDocumentUtil.recordEmbeddedStreamException(e, parentMetadata);
+        List<HSLFShape> shapes = getShapes(shapeContainer);
+        if (shapes == null) {
             return;
         }
-
         for (HSLFShape shape : shapes) {
+            //handle ActiveXShape, movie shape?
             if (shape instanceof HSLFObjectShape) {
                 HSLFObjectShape oleShape = (HSLFObjectShape) shape;
                 HSLFObjectData data = null;
@@ -520,4 +543,17 @@ public class HSLFExtractor extends AbstractPOIFSExtractor {
             }
         }
     }
+
+    //Can return null!
+    private List<HSLFShape> getShapes(ShapeContainer shapeContainer) {
+        try {
+            return shapeContainer.getShapes();
+        } catch (NullPointerException e) {
+            // Sometimes HSLF hits problems
+            // Please open POI bugs for any you come across!
+            EmbeddedDocumentUtil.recordEmbeddedStreamException(e, parentMetadata);
+            return null;
+        }
+    }
+
 }
diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java
index 5d34b2e..d2bc790 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java
@@ -17,8 +17,6 @@
 package org.apache.tika.parser.microsoft;
 
 
-import org.apache.tika.config.Field;
-
 import java.io.Serializable;
 
 public class OfficeParserConfig implements Serializable {
@@ -30,6 +28,8 @@ public class OfficeParserConfig implements Serializable {
     private boolean includeShapeBasedContent = true;
     private boolean includeHeadersAndFooters = true;
     private boolean includeMissingRows = false;
+    private boolean includeSlideNotes = true;
+    private boolean includeSlideMasterContent = true;
     private boolean concatenatePhoneticRuns = true;
 
     private boolean useSAXDocxExtractor = false;
@@ -206,6 +206,44 @@ public class OfficeParserConfig implements Serializable {
     public boolean getIncludeMissingRows() {
         return includeMissingRows;
     }
+
+    public boolean getIncludeSlideNotes() {
+        return includeSlideNotes;
+    }
+
+    /**
+     * Whether or not to process slide notes content.  If set
+     * to <code>false</code>, the parser will skip the text content
+     * and all embedded objects from the slide notes in ppt and ppt[xm].
+     * The default is <code>true</code>.
+     *
+     * @param includeSlideNotes whether or not to process slide notes
+     * @since 1.19.1
+     */
+    public void setIncludeSlideNotes(boolean includeSlideNotes) {
+        this.includeSlideNotes = includeSlideNotes;
+    }
+
+    /**
+     * @since 1.19.1
+     * @return whether or not to process content in slide masters
+     */
+    public boolean getIncludeSlideMasterContent() {
+        return includeSlideMasterContent;
+    }
+
+    /**
+     * Whether or not to include contents from any of the three
+     * types of masters -- slide, notes, handout -- in a .ppt or ppt[xm] file.
+     * If set to <code>false</code>, the parser will not extract
+     * text or embedded objects from any of the masters.
+     *
+     * @since 1.19.1
+     * @param includeSlideMasterContent
+     */
+    public void setIncludeSlideMasterContent(boolean includeSlideMasterContent) {
+        this.includeSlideMasterContent = includeSlideMasterContent;
+    }
 }
 
 
diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
index 10ff76e..ac6e278 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
@@ -122,20 +122,22 @@ public class SXSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
             }
         }
 
-        handleGeneralTextContainingPart(XSLFRelation.SLIDE_MASTER.getRelation(),
-                "slide-master",
-                mainDocument,
-                metadata,
-                new PlaceHolderSkipper(new OOXMLWordAndPowerPointTextHandler(
-                        new OOXMLTikaBodyPartHandler(xhtml), new HashMap<String, String>())));
-
-        handleGeneralTextContainingPart(HANDOUT_MASTER,
-                "slide-handout-master",
-                mainDocument,
-                metadata,
-                new OOXMLWordAndPowerPointTextHandler(
-                        new OOXMLTikaBodyPartHandler(xhtml), new HashMap<String, String>())
-        );
+        if (config.getIncludeSlideMasterContent()) {
+            handleGeneralTextContainingPart(XSLFRelation.SLIDE_MASTER.getRelation(),
+                    "slide-master",
+                    mainDocument,
+                    metadata,
+                    new PlaceHolderSkipper(new OOXMLWordAndPowerPointTextHandler(
+                            new OOXMLTikaBodyPartHandler(xhtml), new HashMap<String, String>())));
+
+            handleGeneralTextContainingPart(HANDOUT_MASTER,
+                    "slide-handout-master",
+                    mainDocument,
+                    metadata,
+                    new OOXMLWordAndPowerPointTextHandler(
+                            new OOXMLTikaBodyPartHandler(xhtml), new HashMap<String, String>())
+            );
+        }
     }
 
     private void loadCommentAuthors() {
@@ -195,26 +197,29 @@ public class SXSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
 
         xhtml.endElement("div");
 
+        if (config.getIncludeSlideMasterContent()) {
+            handleGeneralTextContainingPart(XSLFRelation.SLIDE_LAYOUT.getRelation(),
+                    "slide-master-content", slidePart,
+                    metadata,
+                    new PlaceHolderSkipper(new OOXMLWordAndPowerPointTextHandler(
+                            new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships))
+            );
+        }
+        if (config.getIncludeSlideNotes()) {
+            handleGeneralTextContainingPart(XSLFRelation.NOTES.getRelation(),
+                    "slide-notes", slidePart,
+                    metadata,
+                    new OOXMLWordAndPowerPointTextHandler(
+                            new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships));
+            if (config.getIncludeSlideMasterContent()) {
+                handleGeneralTextContainingPart(XSLFRelation.NOTES_MASTER.getRelation(),
+                        "slide-notes-master", slidePart,
+                        metadata,
+                        new OOXMLWordAndPowerPointTextHandler(
+                                new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships));
 
-        handleGeneralTextContainingPart(XSLFRelation.SLIDE_LAYOUT.getRelation(),
-                "slide-master-content", slidePart,
-                metadata,
-                new PlaceHolderSkipper(new OOXMLWordAndPowerPointTextHandler(
-                        new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships))
-                );
-
-        handleGeneralTextContainingPart(XSLFRelation.NOTES.getRelation(),
-                "slide-notes", slidePart,
-                metadata,
-                new OOXMLWordAndPowerPointTextHandler(
-                        new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships));
-
-        handleGeneralTextContainingPart(XSLFRelation.NOTES_MASTER.getRelation(),
-                "slide-notes-master", slidePart,
-                metadata,
-                new OOXMLWordAndPowerPointTextHandler(
-                        new OOXMLTikaBodyPartHandler(xhtml), linkedRelationships));
-
+            }
+        }
         handleGeneralTextContainingPart(XSLFRelation.COMMENTS.getRelation(),
                 null, slidePart,
                 metadata,
diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java
index 3d929ba..c63fcb3 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java
@@ -110,29 +110,32 @@ public class XSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
             extractContent(slide.getShapes(), false, xhtml, slideDesc);
             xhtml.endElement("div");
 
-            // slide layout which is the master sheet for this slide
-            xhtml.startElement("div", "class", "slide-master-content");
-            XSLFSlideLayout slideLayout = slide.getMasterSheet();
-            extractContent(slideLayout.getShapes(), true, xhtml, null);
-            xhtml.endElement("div");
-
-            // slide master which is the master sheet for all text layouts
-            XSLFSheet slideMaster = slideLayout.getMasterSheet();
-            extractContent(slideMaster.getShapes(), true, xhtml, null);
-
-            // notes (if present)
-            XSLFNotes slideNotes = slide.getNotes();
-            if (slideNotes != null) {
-                xhtml.startElement("div", "class", "slide-notes");
-
-                extractContent(slideNotes.getShapes(), false, xhtml, slideDesc);
+            if (config.getIncludeSlideMasterContent()) {
+                // slide layout which is the master sheet for this slide
+                xhtml.startElement("div", "class", "slide-master-content");
+                XSLFSlideLayout slideLayout = slide.getMasterSheet();
+                extractContent(slideLayout.getShapes(), true, xhtml, null);
+                xhtml.endElement("div");
 
-                // master sheet for this notes
-                XSLFNotesMaster notesMaster = slideNotes.getMasterSheet();
-                if (notesMaster != null) {
-                    extractContent(notesMaster.getShapes(), true, xhtml, null);
+                // slide master which is the master sheet for all text layouts
+                XSLFSheet slideMaster = slideLayout.getMasterSheet();
+                extractContent(slideMaster.getShapes(), true, xhtml, null);
+            }
+            if (config.getIncludeSlideNotes()) {
+                // notes (if present)
+                XSLFNotes slideNotes = slide.getNotes();
+                if (slideNotes != null) {
+                    xhtml.startElement("div", "class", "slide-notes");
+
+                    extractContent(slideNotes.getShapes(), false, xhtml, slideDesc);
+
+                    // master sheet for this notes
+                    XSLFNotesMaster notesMaster = slideNotes.getMasterSheet();
+                    if (notesMaster != null) {
+                        extractContent(notesMaster.getShapes(), true, xhtml, null);
+                    }
+                    xhtml.endElement("div");
                 }
-                xhtml.endElement("div");
             }
 
             // comments (if present)
@@ -193,6 +196,7 @@ public class XSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
     private void extractContent(List<? extends XSLFShape> shapes, boolean skipPlaceholders, XHTMLContentHandler xhtml, String slideDesc)
             throws SAXException {
         for (XSLFShape sh : shapes) {
+
             if (sh instanceof XSLFTextShape) {
                 XSLFTextShape txt = (XSLFTextShape) sh;
                 Placeholder ph = txt.getTextType();
@@ -202,7 +206,9 @@ public class XSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
                 boolean inHyperlink = false;
                 for (XSLFTextParagraph p : txt.getTextParagraphs()) {
                     xhtml.startElement("p");
-
+                    if (! config.getIncludeHeadersAndFooters() && p.isHeaderOrFooter()) {
+                        continue;
+                    }
                     for (XSLFTextRun run : p.getTextRuns()) {
                         //TODO: add check for targetmode=external into POI
                         //then check to confirm that the urls are actually
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/PowerPointParserTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/PowerPointParserTest.java
index dbba939..658c0d5 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/PowerPointParserTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/PowerPointParserTest.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.ctakes.typesystem.type.syntax.O;
 import org.apache.tika.TikaTest;
 import org.apache.tika.exception.EncryptedDocumentException;
 import org.apache.tika.metadata.Metadata;
@@ -122,6 +123,23 @@ public class PowerPointParserTest extends TikaTest {
     }
 
     @Test
+    @Ignore("not sure why this isn't working")
+    public void testSkipHeaderFooter() throws Exception {
+        //now test turning off header/footer
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeHeadersAndFooters(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        String xml = getXML("testPPT_various.ppt", context).xml;
+        //"This is the header text" should show up as a notes header
+        //however, it is currently being extracted while we process notes
+        //as just a regular HSLFTextParagraph with a value of "false"
+        //for p.isHeaderOrFooter().
+        assertNotContained("This is the header text", xml);
+
+    }
+
+    @Test
     public void testMasterFooter() throws Exception {
         ContentHandler handler = new BodyContentHandler();
         Metadata metadata = new Metadata();
@@ -141,6 +159,18 @@ public class PowerPointParserTest extends TikaTest {
         assertEquals(-1, content.indexOf("*"));
     }
 
+    @Test
+    @Ignore("not working")
+    public void testTurningOffMasterFooter() throws Exception {
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        assertNotContained("Master footer",
+                getXML("testPPT_masterFooter.ppt", context).xml);
+    }
+
     /**
      * TIKA-712 Master Slide Text from PPT and PPTX files
      *  should be extracted too
@@ -163,6 +193,15 @@ public class PowerPointParserTest extends TikaTest {
 
         //TIKA-1171, POI-62591
         assertEquals(-1, content.indexOf("*"));
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        content = getXML("testPPT_masterText.ppt", context).xml;
+        assertNotContained("Text that I added", content);
+
     }
 
     @Test
@@ -182,6 +221,15 @@ public class PowerPointParserTest extends TikaTest {
         assertEquals(-1, content.indexOf("Click to edit Master"));
         //TIKA-1171, POI-62591
         assertEquals(-1, content.indexOf("*"));
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        content = getXML("testPPT_masterText2.ppt", context).xml;
+        assertNotContained("Text that I added", content);
+
     }
 
     /**
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java
index a2eb625..ce8ea28 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java
@@ -770,6 +770,18 @@ public class OOXMLParserTest extends TikaTest {
     }
 
     @Test
+    public void testSkipHeaderFooter() throws Exception {
+        //now test turning off header/footer
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeHeadersAndFooters(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        String xml = getXML("testPPT_various.pptx", context).xml;
+        assertNotContained("This is the header text", xml);
+
+    }
+
+    @Test
     public void testCommentPPTX() throws Exception {
         XMLResult r = getXML("testPPT_comment.pptx");
         assertContains("<p class=\"slide-comment\"><b>Allison, Timothy B. (ATB)", r.xml);
@@ -789,6 +801,21 @@ public class OOXMLParserTest extends TikaTest {
         assertContains("Master footer is here", content);
     }
 
+    @Test
+    @Ignore("can't tell why this isn't working")
+    public void testTurningOffMasterContent() throws Exception {
+        //now test turning off master content
+
+        //the underlying xml has "Master footer" in
+        //the actual slide's xml, not just in the master slide.
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        String xml = getXML("testPPT_masterFooter.pptx", context).xml;
+        assertNotContained("Master footer", xml);
+    }
+
     /**
      * TIKA-712 Master Slide Text from PPT and PPTX files
      * should be extracted too
@@ -805,6 +832,14 @@ public class OOXMLParserTest extends TikaTest {
 
         String content = handler.toString();
         assertContains("Text that I added to the master slide", content);
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        content = getXML("testPPT_masterText.pptx", context).xml;
+        assertNotContained("Text that I added", content);
     }
 
     @Test
@@ -819,6 +854,14 @@ public class OOXMLParserTest extends TikaTest {
 
         String content = handler.toString();
         assertContains("Text that I added to the master slide", content);
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        content = getXML("testPPT_masterText2.pptx", context).xml;
+        assertNotContained("Text that I added", content);
     }
 
     @Test
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java
index cb935c5..651e5f5 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java
@@ -369,6 +369,21 @@ public class SXSLFExtractorTest extends TikaTest {
                 getXML("testPPT_masterFooter.pptx", parseContext).xml);
     }
 
+    @Test
+    @Ignore("can't tell why this isn't working")
+    public void testTurningOffMasterContent() throws Exception {
+        //now test turning off master content
+
+        //the underlying xml has "Master footer" in
+        //the actual slide's xml, not just in the master slide.
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        config.setUseSAXPptxExtractor(true);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+        String xml = getXML("testPPT_masterFooter.pptx", context).xml;
+        assertNotContained("Master footer", xml);
+    }
     /**
      * TIKA-712 Master Slide Text from PPT and PPTX files
      * should be extracted too
@@ -377,12 +392,32 @@ public class SXSLFExtractorTest extends TikaTest {
     public void testMasterText() throws Exception {
         assertContains("Text that I added to the master slide",
                 getXML("testPPT_masterText.pptx", parseContext).xml);
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        config.setUseSAXPptxExtractor(true);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+
+        assertNotContained("Text that I added",
+                getXML("testPPT_masterText.pptx", context).xml);
     }
 
     @Test
     public void testMasterText2() throws Exception {
         assertContains("Text that I added to the master slide",
                 getXML("testPPT_masterText2.pptx", parseContext).xml);
+
+        //now test turning off master content
+        OfficeParserConfig config = new OfficeParserConfig();
+        config.setIncludeSlideMasterContent(false);
+        config.setUseSAXPptxExtractor(true);
+        ParseContext context = new ParseContext();
+        context.set(OfficeParserConfig.class, config);
+
+        assertNotContained("Text that I added",
+                getXML("testPPT_masterText2.pptx", context).xml);
     }
 
     @Test