This is an automated email from the ASF dual-hosted git repository. tballison pushed a commit to branch TIKA-4790-default-to-sax-ooxml in repository https://gitbox.apache.org/repos/asf/tika.git
commit 36a448f800a0f794b2acbe642fb5b01f79a3ce70 Author: tallison <[email protected]> AuthorDate: Wed Jul 15 08:49:31 2026 -0400 TIKA-4790 -- make sax parsing default in 3.x --- CHANGES.txt | 10 +++---- .../tika/parser/microsoft/OfficeParserConfig.java | 20 +++++++------- .../parser/microsoft/ooxml/OOXMLParserTest.java | 31 ++++++++++++++++------ .../parser/microsoft/ooxml/SXSLFExtractorTest.java | 13 +++------ .../parser/microsoft/ooxml/SXWPFExtractorTest.java | 24 +++++------------ 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 106fe2a36c..626793f7e4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,11 +4,11 @@ Release 3.3.2 - (unreleased) /status endpoints are selected; the server refuses to start otherwise. Previously listing the endpoint was treated as sufficient consent (TIKA-4760). - * Port the 4.x SAX-based OOXML parsers to 3.x. The docx/pptx/xlsx/vsdx SAX parsers - gain field-code hyperlink extraction, inlined footnotes/endnotes/comments, - balanced-XHTML recovery on error, and XMLBeans-free xlsx/xlsb reading. The SAX - docx/pptx parsers stay opt-in via useSAXDocxExtractor/useSAXPptxExtractor, so DOM - remains the default (TIKA-4692, TIKA-4708). + * Port the 4.x SAX-based OOXML parsers to 3.x and make SAX default. + The docx/pptx/xlsx/vsdx SAX parsers gain field-code hyperlink extraction, + inlined footnotes/endnotes/comments, balanced-XHTML recovery on error, and XMLBeans-free + xlsx/xlsb reading. The DOM docx/pptx parsers can still be configured via + useSAXDocxExtractor/useSAXPptxExtractor (TIKA-4692, TIKA-4708, TIKA-4790). Release 3.3.1 - 5/20/2026 diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java index feeaae1b51..ffa7dd3a02 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParserConfig.java @@ -32,8 +32,8 @@ public class OfficeParserConfig implements Serializable { private boolean includeSlideMasterContent = true; private boolean concatenatePhoneticRuns = true; - private boolean useSAXDocxExtractor = false; - private boolean useSAXPptxExtractor = false; + private boolean useSAXDocxExtractor = true; + private boolean useSAXPptxExtractor = true; private boolean preferAlternateContentChoice = true; @@ -142,11 +142,11 @@ public class OfficeParserConfig implements Serializable { } /** - * Use the experimental SAX-based streaming DOCX parser? - * If set to <code>false</code>, the classic parser will be used; if <code>true</code>, - * the new experimental parser will be used. + * Use the SAX-based streaming DOCX parser? + * If set to <code>true</code>, the SAX-based streaming parser will be used; + * if <code>false</code>, the classic DOM parser will be used. * <p/> - * Default: <code>false</code> (classic DOM parser) + * Default: <code>true</code> (SAX streaming parser) * * @param useSAXDocxExtractor */ @@ -159,11 +159,11 @@ public class OfficeParserConfig implements Serializable { } /** - * Use the experimental SAX-based streaming DOCX parser? - * If set to <code>false</code>, the classic parser will be used; if <code>true</code>, - * the new experimental parser will be used. + * Use the SAX-based streaming PPTX parser? + * If set to <code>true</code>, the SAX-based streaming parser will be used; + * if <code>false</code>, the classic DOM parser will be used. * <p/> - * Default: <code>false</code> (classic DOM parser) + * Default: <code>true</code> (SAX streaming parser) * * @param useSAXPptxExtractor */ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java index b5504dc6ed..8185a41985 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLParserTest.java @@ -374,13 +374,26 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { assertContains("<div class=\"endnote\">", xmlResult.xml); } + /** + * The SAX extractors are the default as of Tika 3.x. A handful of tests below + * assert on markup that only the classic DOM extractors produce, so they force DOM. + */ + private static ParseContext domParseContext() { + OfficeParserConfig config = new OfficeParserConfig(); + config.setUseSAXDocxExtractor(false); + config.setUseSAXPptxExtractor(false); + ParseContext context = new ParseContext(); + context.set(OfficeParserConfig.class, config); + return context; + } + /** * Test that the word converter is able to generate the * correct HTML for the document */ @Test public void testWordHTML() throws Exception { - XMLResult result = getXML("testWORD.docx"); + XMLResult result = getXML("testWORD.docx", domParseContext()); String xml = result.xml; Metadata metadata = result.metadata; assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document", @@ -409,7 +422,7 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { // Paragraphs with other styles assertTrue(xml.contains("<p class=\"signature\">This one")); - result = getXML("testWORD_3imgs.docx"); + result = getXML("testWORD_3imgs.docx", domParseContext()); xml = result.xml; // Images 2-4 (there is no 1!) @@ -425,7 +438,7 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { // TIKA-692: test document containing multiple // character runs within a bold tag: - xml = getXML("testWORD_bold_character_runs.docx").xml; + xml = getXML("testWORD_bold_character_runs.docx", domParseContext()).xml; // Make sure bold text arrived as single // contiguous string even though Word parser @@ -434,7 +447,7 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { // TIKA-692: test document containing multiple // character runs within a bold tag: - xml = getXML("testWORD_bold_character_runs2.docx").xml; + xml = getXML("testWORD_bold_character_runs2.docx", domParseContext()).xml; // Make sure bold text arrived as single // contiguous string even though Word parser @@ -537,14 +550,14 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { @Test public void testTextDecorationNested() throws Exception { - String xml = getXML("testWORD_various.docx").xml; + String xml = getXML("testWORD_various.docx", domParseContext()).xml; assertContains("<i>ita<s>li</s>c</i>", xml); assertContains("<i>ita<s>l<u>i</u></s>c</i>", xml); assertContains("<i><u>unde<s>r</s>line</u></i>", xml); //confirm that spaces aren't added for </s> and </u> - String txt = getText("testWORD_various.docx"); + String txt = getText("testWORD_various.docx", new Metadata(), domParseContext()); assertContainsCount("italic", txt, 3); assertNotContained("ita ", txt); @@ -708,8 +721,10 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { @Test public void testSkipHeaderFooter() throws Exception { //now test turning off header/footer + //header/footer suppression for pptx is only implemented in the DOM extractor OfficeParserConfig config = new OfficeParserConfig(); config.setIncludeHeadersAndFooters(false); + config.setUseSAXPptxExtractor(false); ParseContext context = new ParseContext(); context.set(OfficeParserConfig.class, config); String xml = getXML("testPPT_various.pptx", context).xml; @@ -904,7 +919,7 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { // TIKA-997: @Test public void testEmbeddedZipInPPTX() throws Exception { - String xml = getXML("test_embedded_zip.pptx").xml; + String xml = getXML("test_embedded_zip.pptx", domParseContext()).xml; int h = xml.indexOf("<div class=\"embedded\" id=\"slide1_rId3\" />"); int i = xml.indexOf("Send me a note"); int j = xml.indexOf("<div class=\"embedded\" id=\"slide2_rId4\" />"); @@ -977,7 +992,7 @@ public class OOXMLParserTest extends MultiThreadedTikaTest { // TIKA-1032: @Test public void testEmbeddedPPTXTwoSlides() throws Exception { - String xml = getXML("testPPT_embedded_two_slides.pptx").xml; + String xml = getXML("testPPT_embedded_two_slides.pptx", domParseContext()).xml; assertContains("<div class=\"embedded\" id=\"slide1_rId7\" />", xml); assertContains("<div class=\"embedded\" id=\"slide2_rId7\" />", xml); } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java index 48de3013ee..534413c894 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXSLFExtractorTest.java @@ -51,10 +51,9 @@ public class SXSLFExtractorTest extends TikaTest { @BeforeEach public void setUp() { + //SAX is the default OOXML extractor as of Tika 3.x; an unconfigured + //context exercises (and verifies) that default. parseContext = new ParseContext(); - officeParserConfig.setUseSAXPptxExtractor(true); - parseContext.set(OfficeParserConfig.class, officeParserConfig); - } @Test @@ -345,7 +344,6 @@ public class SXSLFExtractorTest extends TikaTest { //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; @@ -364,7 +362,6 @@ public class SXSLFExtractorTest extends TikaTest { //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); @@ -379,7 +376,6 @@ public class SXSLFExtractorTest extends TikaTest { //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); @@ -397,9 +393,7 @@ public class SXSLFExtractorTest extends TikaTest { ParseContext context = new ParseContext(); context.set(Locale.class, Locale.US); - OfficeParserConfig officeParserConfig = new OfficeParserConfig(); - officeParserConfig.setUseSAXPptxExtractor(true); - context.set(OfficeParserConfig.class, officeParserConfig); + context.set(OfficeParserConfig.class, new OfficeParserConfig()); getXML("testPPT_custom_props.pptx", metadata, parseContext); assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation", @@ -529,7 +523,6 @@ public class SXSLFExtractorTest extends TikaTest { ParseContext context = new ParseContext(); OfficeParserConfig officeParserConfig = new OfficeParserConfig(); officeParserConfig.setExtractMacros(true); - officeParserConfig.setUseSAXPptxExtractor(true); context.set(OfficeParserConfig.class, officeParserConfig); Metadata minExpected = new Metadata(); diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXWPFExtractorTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXWPFExtractorTest.java index 65a73faf3a..e5a17032d9 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXWPFExtractorTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/SXWPFExtractorTest.java @@ -54,12 +54,9 @@ public class SXWPFExtractorTest extends TikaTest { @BeforeEach public void setUp() { + //SAX is the default OOXML extractor as of Tika 3.x; an unconfigured + //context exercises (and verifies) that default. parseContext = new ParseContext(); - OfficeParserConfig officeParserConfig = new OfficeParserConfig(); - officeParserConfig.setUseSAXDocxExtractor(true); - officeParserConfig.setUseSAXPptxExtractor(true); - parseContext.set(OfficeParserConfig.class, officeParserConfig); - } @Test @@ -479,7 +476,6 @@ public class SXWPFExtractorTest extends TikaTest { ParseContext pc = new ParseContext(); OfficeParserConfig officeParserConfig = new OfficeParserConfig(); officeParserConfig.setIncludeDeletedContent(true); - officeParserConfig.setUseSAXDocxExtractor(true); officeParserConfig.setIncludeMoveFromContent(true); pc.set(OfficeParserConfig.class, officeParserConfig); @@ -505,7 +501,6 @@ public class SXWPFExtractorTest extends TikaTest { ParseContext pc = new ParseContext(); OfficeParserConfig officeParserConfig = new OfficeParserConfig(); officeParserConfig.setIncludeShapeBasedContent(false); - officeParserConfig.setUseSAXDocxExtractor(true); pc.set(OfficeParserConfig.class, officeParserConfig); String xml = getXML("testWORD_text_box.docx", pc).xml; assertContains("This text is directly in the body of the document.", xml); @@ -572,11 +567,8 @@ public class SXWPFExtractorTest extends TikaTest { Metadata m = new Metadata(); PasswordProvider passwordProvider = metadata -> "tika"; - OfficeParserConfig opc = new OfficeParserConfig(); - opc.setUseSAXDocxExtractor(true); ParseContext passwordContext = new ParseContext(); passwordContext.set(org.apache.tika.parser.PasswordProvider.class, passwordProvider); - passwordContext.set(OfficeParserConfig.class, opc); for (Map.Entry<String, String> e : tests.entrySet()) { assertContains(e.getValue(), getXML(e.getKey(), passwordContext).xml); } @@ -725,7 +717,6 @@ public class SXWPFExtractorTest extends TikaTest { ParseContext context = new ParseContext(); OfficeParserConfig officeParserConfig = new OfficeParserConfig(); officeParserConfig.setExtractMacros(true); - officeParserConfig.setUseSAXDocxExtractor(true); context.set(OfficeParserConfig.class, officeParserConfig); metadataList = getRecursiveMetadata("testWORD_macros.docm", context); @@ -802,7 +793,6 @@ public class SXWPFExtractorTest extends TikaTest { ParseContext parseContext = new ParseContext(); OfficeParserConfig officeParserConfig = new OfficeParserConfig(); officeParserConfig.setIncludeHeadersAndFooters(false); - officeParserConfig.setUseSAXDocxExtractor(true); parseContext.set(OfficeParserConfig.class, officeParserConfig); String xml = getXML("testWORD_various.docx", parseContext).xml; assertNotContained("This is the header text.", xml); @@ -811,15 +801,13 @@ public class SXWPFExtractorTest extends TikaTest { @Test public void testDOCXPhoneticStrings() throws Exception { - OfficeParserConfig config = new OfficeParserConfig(); - config.setUseSAXDocxExtractor(true); - ParseContext parseContext = new ParseContext(); - parseContext.set(OfficeParserConfig.class, config); assertContains("\u6771\u4EAC (\u3068\u3046\u304D\u3087\u3046)", - getXML("testWORD_phonetic.docx", parseContext).xml); - + getXML("testWORD_phonetic.docx").xml); + OfficeParserConfig config = new OfficeParserConfig(); config.setConcatenatePhoneticRuns(false); + ParseContext parseContext = new ParseContext(); + parseContext.set(OfficeParserConfig.class, config); String xml = getXML("testWORD_phonetic.docx", parseContext).xml; assertContains("\u6771\u4EAC", xml); assertNotContained("\u3068", xml);
