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 2026/04/09 11:38:12 UTC
(tika) branch main updated: TIKA-4707 -- rm dom parsers for docx/pptx (#2747)
This is an automated email from the ASF dual-hosted git repository.
tallison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 8501894c11 TIKA-4707 -- rm dom parsers for docx/pptx (#2747)
8501894c11 is described below
commit 8501894c11bf9ddc748e351de3c3aa6e7751295d
Author: Tim Allison <ta...@apache.org>
AuthorDate: Thu Apr 9 07:38:06 2026 -0400
TIKA-4707 -- rm dom parsers for docx/pptx (#2747)
---
.../tika-parser-microsoft-module/pom.xml | 6 +
.../tika/parser/microsoft/OfficeParserConfig.java | 37 --
.../microsoft/ooxml/AbstractOOXMLExtractor.java | 36 +-
.../parser/microsoft/ooxml/MetadataExtractor.java | 279 +-------
.../parser/microsoft/ooxml/OOXMLExtractor.java | 15 -
.../microsoft/ooxml/OOXMLExtractorFactory.java | 239 +++----
.../ooxml/POIXMLTextExtractorDecorator.java | 51 --
.../microsoft/ooxml/SAXBasedMetadataExtractor.java | 1 -
.../ooxml/SXSLFPowerPointExtractorDecorator.java | 11 +-
.../ooxml/SXWPFWordExtractorDecorator.java | 10 +-
.../microsoft/ooxml/TikaXSSFBCommentsTable.java | 137 ++++
.../ooxml/TikaXSSFBSharedStringsTable.java | 159 +++++
.../microsoft/ooxml/VSDXExtractorDecorator.java | 174 +++++
.../ooxml/XSLFPowerPointExtractorDecorator.java | 412 ------------
.../ooxml/XSSFBExcelExtractorDecorator.java | 98 +--
.../ooxml/XSSFExcelExtractorDecorator.java | 24 +-
.../ooxml/XWPFWordExtractorDecorator.java | 734 ---------------------
.../microsoft/ooxml/xps/XPSExtractorDecorator.java | 16 +-
.../microsoft/ooxml/xps/XPSTextExtractor.java | 89 ---
.../xslf/XSLFEventBasedPowerPointExtractor.java | 212 +-----
.../ooxml/xwpf/XWPFEventBasedWordExtractor.java | 386 +----------
.../microsoft/ooxml/AbstractOOXMLDocxTest.java | 601 -----------------
.../microsoft/ooxml/AbstractOOXMLPptxTest.java | 363 ----------
.../parser/microsoft/ooxml/OOXMLDocxDOMTest.java | 133 ----
.../parser/microsoft/ooxml/OOXMLDocxSAXTest.java | 505 ++++++++++++--
.../parser/microsoft/ooxml/OOXMLPptxDOMTest.java | 204 ------
.../parser/microsoft/ooxml/OOXMLPptxSAXTest.java | 341 ++++++++--
.../parser/microsoft/ooxml/VSDXParserTest.java | 62 ++
.../resources/configs/tika-config-sax-docx.json | 7 +-
.../resources/configs/tika-config-sax-macros.json | 4 +-
.../resources/test-documents/testVISIO_60489.vsdx | Bin 0 -> 44426 bytes
.../resources/test-documents/testVISIO_text.vsdx | Bin 0 -> 22343 bytes
.../ooxml/AbstractOOXMLDocxPackageTest.java | 51 --
.../ooxml/AbstractOOXMLPptxPackageTest.java | 41 --
.../microsoft/ooxml/OOXMLDocxDOMPackageTest.java | 94 ---
.../microsoft/ooxml/OOXMLDocxSAXPackageTest.java | 32 +-
.../microsoft/ooxml/OOXMLPptxDOMPackageTest.java | 27 -
.../microsoft/ooxml/OOXMLPptxSAXPackageTest.java | 26 +-
38 files changed, 1512 insertions(+), 4105 deletions(-)
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/pom.xml b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/pom.xml
index a3c7e1f1c8..4231df7044 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/pom.xml
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/pom.xml
@@ -93,6 +93,12 @@
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi-ooxml-lite</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<!-- needed by jackcess -->
<dependency>
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 363b0a0773..bb2ff73af5 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,9 +32,6 @@ public class OfficeParserConfig implements Serializable {
private boolean includeSlideMasterContent = true;
private boolean concatenatePhoneticRuns = true;
- private boolean useSAXDocxExtractor = false;
- private boolean useSAXPptxExtractor = false;
-
private boolean preferAlternateContentChoice = true;
private boolean writeSelectHeadersInBody = false;
@@ -142,40 +139,6 @@ public class OfficeParserConfig implements Serializable {
this.includeHeadersAndFooters = includeHeadersAndFooters;
}
- public boolean isUseSAXDocxExtractor() {
- return useSAXDocxExtractor;
- }
-
- /**
- * 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.
- * <p/>
- * Default: <code>false</code> (classic DOM parser)
- *
- * @param useSAXDocxExtractor
- */
- public void setUseSAXDocxExtractor(boolean useSAXDocxExtractor) {
- this.useSAXDocxExtractor = useSAXDocxExtractor;
- }
-
- public boolean isUseSAXPptxExtractor() {
- return useSAXPptxExtractor;
- }
-
- /**
- * 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.
- * <p/>
- * Default: <code>false</code> (classic DOM parser)
- *
- * @param useSAXPptxExtractor
- */
- public void setUseSAXPptxExtractor(boolean useSAXPptxExtractor) {
- this.useSAXPptxExtractor = useSAXPptxExtractor;
- }
-
/**
* In OOXML, {@code mc:AlternateContent} wraps {@code mc:Choice} (newer/richer
* rendering, e.g. DrawingML text boxes) and {@code mc:Fallback} (degraded VML
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLExtractor.java
index 6beef7c1c4..c686414ed1 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLExtractor.java
@@ -30,8 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
@@ -45,7 +43,6 @@ import org.apache.poi.poifs.filesystem.Ole10Native;
import org.apache.poi.poifs.filesystem.Ole10NativeException;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.xssf.usermodel.XSSFRelation;
-import org.apache.poi.xwpf.usermodel.XWPFRelation;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -93,9 +90,14 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
static final String RELATION_ALTERNATE_FORMAT_CHUNK =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk";
+ private static final String PACK_OBJECT_REL_TYPE =
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
+ private static final String OLE_OBJECT_REL_TYPE =
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
+
protected static final String[] EMBEDDED_RELATIONSHIPS =
new String[]{RELATION_AUDIO, PackageRelationshipTypes.IMAGE_PART,
- POIXMLDocument.PACK_OBJECT_REL_TYPE, PackageRelationshipTypes.CORE_DOCUMENT,
+ PACK_OBJECT_REL_TYPE, PackageRelationshipTypes.CORE_DOCUMENT,
RELATION_DIAGRAM_DATA};
private static final String TYPE_OLE_OBJECT =
"application/vnd.openxmlformats-officedocument.oleObject";
@@ -104,11 +106,11 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
private final EmbeddedDocumentExtractor embeddedExtractor;
private final ParseContext context;
protected OfficeParserConfig config;
- protected POIXMLTextExtractor extractor;
+ protected OPCPackage opcPackage;
- public AbstractOOXMLExtractor(ParseContext context, POIXMLTextExtractor extractor) {
+ public AbstractOOXMLExtractor(ParseContext context, OPCPackage opcPackage) {
this.context = context;
- this.extractor = extractor;
+ this.opcPackage = opcPackage;
embeddedExtractor = EmbeddedDocumentUtil.getEmbeddedDocumentExtractor(context);
// This has already been set by OOXMLParser's call to configure()
@@ -116,18 +118,11 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
this.config = context.get(OfficeParserConfig.class);
}
- /**
- * @see org.apache.tika.parser.microsoft.ooxml.OOXMLExtractor#getDocument()
- */
- public POIXMLDocument getDocument() {
- return (POIXMLDocument) extractor.getDocument();
- }
-
/**
* @see org.apache.tika.parser.microsoft.ooxml.OOXMLExtractor#getMetadataExtractor()
*/
public MetadataExtractor getMetadataExtractor() {
- return new MetadataExtractor(extractor);
+ return new SAXBasedMetadataExtractor(opcPackage, context);
}
ParseContext getParseContext() {
@@ -173,7 +168,6 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
private void handleThumbnail(ContentHandler handler, Metadata metadata) throws SAXException {
try {
- OPCPackage opcPackage = extractor.getPackage();
for (PackageRelationship rel : opcPackage
.getRelationshipsByType(PackageRelationshipTypes.THUMBNAIL)) {
PackagePart tPart = opcPackage.getPart(rel);
@@ -274,7 +268,7 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
if (rel.getTargetMode() != TargetMode.INTERNAL) {
// External target - emit as external reference for security analysis
String type = rel.getRelationshipType();
- if (POIXMLDocument.OLE_OBJECT_REL_TYPE.equals(type)) {
+ if (OLE_OBJECT_REL_TYPE.equals(type)) {
emitExternalRef(xhtml, "externalOleObject", targetURI.toString());
parentMetadata.set(Office.HAS_EXTERNAL_OLE_OBJECTS, true);
} else if (PackageRelationshipTypes.IMAGE_PART.equals(type)) {
@@ -293,7 +287,7 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
}
EmbeddedPartMetadata embeddedPartMetadata = embeddedPartMetadataMap.get(rel.getId());
String type = rel.getRelationshipType();
- if (POIXMLDocument.OLE_OBJECT_REL_TYPE.equals(type) &&
+ if (OLE_OBJECT_REL_TYPE.equals(type) &&
TYPE_OLE_OBJECT.equals(target.getContentType())) {
handleEmbeddedOLE(target, xhtml, sourceDesc + rel.getId(), parentMetadata,
embeddedPartMetadata);
@@ -308,8 +302,8 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
}
} else if (RELATION_MEDIA.equals(type) || RELATION_VIDEO.equals(type) ||
RELATION_AUDIO.equals(type) ||
- POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(type) ||
- POIXMLDocument.OLE_OBJECT_REL_TYPE.equals(type)) {
+ PACK_OBJECT_REL_TYPE.equals(type) ||
+ OLE_OBJECT_REL_TYPE.equals(type)) {
handleEmbeddedFile(target, xhtml, sourceDesc + rel.getId(),
embeddedPartMetadata,
TikaCoreProperties.EmbeddedResourceType.ATTACHMENT);
@@ -566,7 +560,7 @@ public abstract class AbstractOOXMLExtractor implements OOXMLExtractor {
Map<String, String> linkedRelationships = new HashMap<>();
try {
PackageRelationshipCollection prc =
- bodyPart.getRelationshipsByType(XWPFRelation.HYPERLINK.getRelation());
+ bodyPart.getRelationshipsByType(PackageRelationshipTypes.HYPERLINK_PART);
for (int i = 0; i < prc.size(); i++) {
PackageRelationship pr = prc.getRelationship(i);
if (pr == null) {
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/MetadataExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/MetadataExtractor.java
index 97efe3e186..f983872395 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/MetadataExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/MetadataExtractor.java
@@ -16,288 +16,15 @@
*/
package org.apache.tika.parser.microsoft.ooxml;
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.Optional;
-
-import org.apache.poi.ooxml.POIXMLProperties;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
-import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
-import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException;
-import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty;
-import org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties;
-
import org.apache.tika.exception.TikaException;
-import org.apache.tika.metadata.DublinCore;
import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.metadata.OfficeOpenXMLCore;
-import org.apache.tika.metadata.OfficeOpenXMLExtended;
-import org.apache.tika.metadata.PagedText;
-import org.apache.tika.metadata.Property;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.microsoft.SummaryExtractor;
-import org.apache.tika.parser.microsoft.ooxml.xps.XPSTextExtractor;
-import org.apache.tika.parser.microsoft.ooxml.xslf.XSLFEventBasedPowerPointExtractor;
-import org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor;
/**
- * OOXML metadata extractor.
- * <p/>
- * Currently POI doesn't support metadata extraction for OOXML.
+ * OOXML metadata extractor base class.
*
* @see OOXMLExtractor#getMetadataExtractor()
*/
-public class MetadataExtractor {
-
- private final POIXMLTextExtractor extractor;
-
- public MetadataExtractor(POIXMLTextExtractor extractor) {
- this.extractor = extractor;
- }
-
- public void extract(Metadata metadata) throws TikaException {
- if (extractor.getDocument() != null ||
- ((extractor instanceof XSSFEventBasedExcelExtractor ||
- extractor instanceof XWPFEventBasedWordExtractor ||
- extractor instanceof XSLFEventBasedPowerPointExtractor ||
- extractor instanceof XPSTextExtractor) && extractor.getPackage() != null)) {
- extractMetadata(extractor.getCoreProperties(), metadata);
- extractMetadata(extractor.getExtendedProperties(), metadata);
- extractMetadata(extractor.getCustomProperties(), metadata);
- }
- }
-
- private void extractMetadata(POIXMLProperties.CoreProperties properties, Metadata metadata) {
- PackagePropertiesPart propsHolder = properties.getUnderlyingProperties();
-
- setProperty(metadata, OfficeOpenXMLCore.CATEGORY, propsHolder.getCategoryProperty());
- setProperty(metadata, OfficeOpenXMLCore.CONTENT_STATUS,
- propsHolder.getContentStatusProperty());
- setProperty(metadata, TikaCoreProperties.CREATED, propsHolder.getCreatedProperty());
- addMultiProperty(metadata, TikaCoreProperties.CREATOR, propsHolder.getCreatorProperty());
- setProperty(metadata, TikaCoreProperties.DESCRIPTION, propsHolder.getDescriptionProperty());
- setProperty(metadata, TikaCoreProperties.IDENTIFIER, propsHolder.getIdentifierProperty());
- addProperty(metadata, DublinCore.SUBJECT, propsHolder.getSubjectProperty());
- addProperty(metadata, Office.KEYWORDS, propsHolder.getKeywordsProperty());
- setProperty(metadata, TikaCoreProperties.LANGUAGE, propsHolder.getLanguageProperty());
- setProperty(metadata, TikaCoreProperties.MODIFIER, propsHolder.getLastModifiedByProperty());
- setProperty(metadata, TikaCoreProperties.PRINT_DATE, propsHolder.getLastPrintedProperty());
- setProperty(metadata, TikaCoreProperties.MODIFIED, propsHolder.getModifiedProperty());
- setProperty(metadata, OfficeOpenXMLCore.REVISION, propsHolder.getRevisionProperty());
-
- setProperty(metadata, TikaCoreProperties.TITLE, propsHolder.getTitleProperty());
- setProperty(metadata, OfficeOpenXMLCore.VERSION, propsHolder.getVersionProperty());
-
- }
-
- private void extractMetadata(POIXMLProperties.ExtendedProperties properties,
- Metadata metadata) {
- CTProperties propsHolder = properties.getUnderlyingProperties();
-
- //TIKA-2055, some ooxml files can include unsigned int/long values
- //which cause this exception.
- //For now, catch it and record as '0' because
- //Word converts to '0' on save.
- int totalTime = 0;
- try {
- totalTime = propsHolder.getTotalTime();
- } catch (XmlValueOutOfRangeException e) {
- //swallow for now
- }
- setProperty(metadata, OfficeOpenXMLExtended.APPLICATION, propsHolder.getApplication());
- setProperty(metadata, OfficeOpenXMLExtended.APP_VERSION, propsHolder.getAppVersion());
- setProperty(metadata, TikaCoreProperties.PUBLISHER, propsHolder.getCompany());
- setProperty(metadata, OfficeOpenXMLExtended.COMPANY, propsHolder.getCompany());
- SummaryExtractor
- .addMulti(metadata, OfficeOpenXMLExtended.MANAGER, propsHolder.getManager());
- setProperty(metadata, OfficeOpenXMLExtended.NOTES, propsHolder.getNotes());
- setProperty(metadata, OfficeOpenXMLExtended.PRESENTATION_FORMAT,
- propsHolder.getPresentationFormat());
- setProperty(metadata, OfficeOpenXMLExtended.TEMPLATE, propsHolder.getTemplate());
- setProperty(metadata, OfficeOpenXMLExtended.TOTAL_TIME, totalTime);
- int docSecurityFlag = propsHolder.getDocSecurity();
- setProperty(metadata, OfficeOpenXMLExtended.DOC_SECURITY, docSecurityFlag);
- setProperty(metadata, OfficeOpenXMLExtended.DOC_SECURITY_STRING,
- getDocSecurityString(docSecurityFlag));
- if (propsHolder.getPages() > 0) {
- metadata.set(PagedText.N_PAGES, propsHolder.getPages());
- } else if (propsHolder.getSlides() > 0) {
- metadata.set(PagedText.N_PAGES, propsHolder.getSlides());
- }
-
- // Process the document statistics
- setProperty(metadata, Office.PAGE_COUNT, propsHolder.getPages());
- setProperty(metadata, Office.SLIDE_COUNT, propsHolder.getSlides());
- setProperty(metadata, Office.PARAGRAPH_COUNT, propsHolder.getParagraphs());
- setProperty(metadata, Office.LINE_COUNT, propsHolder.getLines());
- setProperty(metadata, Office.WORD_COUNT, propsHolder.getWords());
- setProperty(metadata, Office.CHARACTER_COUNT, propsHolder.getCharacters());
- setProperty(metadata, Office.CHARACTER_COUNT_WITH_SPACES,
- propsHolder.getCharactersWithSpaces());
- }
-
- private String getDocSecurityString(int docSecurityFlag) {
- //mappings from: https://exiftool.org/TagNames/OOXML.html and
- //https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.extendedproperties.documentsecurity?view=openxml-2.8.1
- switch (docSecurityFlag) {
- case 0:
- return OfficeOpenXMLExtended.SECURITY_NONE;
- case 1:
- return OfficeOpenXMLExtended.SECURITY_PASSWORD_PROTECTED;
- case 2:
- return OfficeOpenXMLExtended.SECURITY_READ_ONLY_RECOMMENDED;
- case 4:
- return OfficeOpenXMLExtended.SECURITY_READ_ONLY_ENFORCED;
- case 8:
- return OfficeOpenXMLExtended.SECURITY_LOCKED_FOR_ANNOTATIONS;
- default:
- return OfficeOpenXMLExtended.SECURITY_UNKNOWN;
- }
- }
-
- private void extractMetadata(POIXMLProperties.CustomProperties properties, Metadata metadata) {
- org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperties props =
- properties.getUnderlyingProperties();
- for (int i = 0; i < props.sizeOfPropertyArray(); i++) {
- CTProperty property = props.getPropertyArray(i);
- String val = null;
- Date date = null;
-
- if (property.isSetLpwstr()) {
- val = property.getLpwstr();
- } else if (property.isSetLpstr()) {
- val = property.getLpstr();
- } else if (property.isSetDate()) {
- date = property.getDate().getTime();
- } else if (property.isSetFiletime()) {
- date = property.getFiletime().getTime();
- } else if (property.isSetBool()) {
- val = Boolean.toString(property.getBool());
- }
-
- // Integers
- else if (property.isSetI1()) {
- val = Integer.toString(property.getI1());
- } else if (property.isSetI2()) {
- val = Integer.toString(property.getI2());
- } else if (property.isSetI4()) {
- val = Integer.toString(property.getI4());
- } else if (property.isSetI8()) {
- val = Long.toString(property.getI8());
- } else if (property.isSetInt()) {
- val = Integer.toString(property.getInt());
- }
-
- // Unsigned Integers
- else if (property.isSetUi1()) {
- val = Integer.toString(property.getUi1());
- } else if (property.isSetUi2()) {
- val = Integer.toString(property.getUi2());
- } else if (property.isSetUi4()) {
- val = Long.toString(property.getUi4());
- } else if (property.isSetUi8()) {
- val = property.getUi8().toString();
- } else if (property.isSetUint()) {
- val = Long.toString(property.getUint());
- }
-
- // Reals
- else if (property.isSetR4()) {
- val = Float.toString(property.getR4());
- } else if (property.isSetR8()) {
- val = Double.toString(property.getR8());
- } else if (property.isSetDecimal()) {
- BigDecimal d = property.getDecimal();
- if (d == null) {
- val = null;
- } else {
- val = d.toPlainString();
- }
- } else if (property.isSetArray()) {
- // TODO Fetch the array values and output
- } else if (property.isSetVector()) {
- // TODO Fetch the vector values and output
- } else if (property.isSetBlob() || property.isSetOblob()) {
- // TODO Decode, if possible
- } else if (property.isSetStream() || property.isSetOstream() ||
- property.isSetVstream()) {
- // TODO Decode, if possible
- } else if (property.isSetStorage() || property.isSetOstorage()) {
- // TODO Decode, if possible
- } else {
- // This type isn't currently supported yet, skip the property
- }
-
- String propName = "custom:" + property.getName();
- if (date != null) {
- Property tikaProp = Property.externalDate(propName);
- metadata.set(tikaProp, date);
- } else if (val != null) {
- metadata.set(propName, val);
- }
- }
- }
-
- private <T> void setProperty(Metadata metadata, Property property, Optional<T> optionalValue) {
- if (!optionalValue.isPresent()) {
- return;
- }
- T value = optionalValue.get();
- if (value instanceof Date) {
- metadata.set(property, (Date) value);
- } else if (value instanceof String) {
- metadata.set(property, (String) value);
- } else if (value instanceof Integer) {
- metadata.set(property, (Integer) value);
- } else if (value instanceof Double) {
- metadata.set(property, (Double) value);
- }
- }
-
- private <T> void addProperty(Metadata metadata, Property property, Optional<T> optionalValue) {
- if (!optionalValue.isPresent()) {
- return;
- }
- T value = optionalValue.get();
- if (value instanceof String) {
- metadata.add(property, (String) value);
- } else {
- throw new IllegalArgumentException(
- "Can't add property of class: " + optionalValue.getClass());
- }
- }
-
- private void setProperty(Metadata metadata, Property property, String value) {
- if (value != null) {
- metadata.set(property, value);
- }
- }
-
- private void setProperty(Metadata metadata, String name, String value) {
- if (value != null) {
- metadata.set(name, value);
- }
- }
-
- private void setProperty(Metadata metadata, Property property, int value) {
- if (value > 0) {
- metadata.set(property, value);
- }
- }
-
- private void setProperty(Metadata metadata, String name, int value) {
- if (value > 0) {
- metadata.set(name, Integer.toString(value));
- }
- }
-
- private void addMultiProperty(Metadata metadata, Property property, Optional<String> value) {
- if (!value.isPresent()) {
- return;
- }
- SummaryExtractor.addMulti(metadata, property, value.get());
- }
+public abstract class MetadataExtractor {
+ public abstract void extract(Metadata metadata) throws TikaException;
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractor.java
index 5c37c9c7b5..8810477bf4 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractor.java
@@ -18,7 +18,6 @@ package org.apache.tika.parser.microsoft.ooxml;
import java.io.IOException;
-import org.apache.poi.ooxml.POIXMLDocument;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
@@ -28,23 +27,9 @@ import org.apache.tika.parser.ParseContext;
/**
* Interface implemented by all Tika OOXML extractors.
- *
- * @see org.apache.poi.ooxml.extractor.POIXMLTextExtractor
*/
public interface OOXMLExtractor {
- /**
- * Returns the opened document.
- *
- * @see org.apache.poi.ooxml.extractor.POIXMLTextExtractor#getDocument()
- */
- POIXMLDocument getDocument();
-
- /**
- * {@link org.apache.poi.ooxml.extractor.POIXMLTextExtractor#getMetadataTextExtractor()}
- * not yet supported
- * for OOXML by POI.
- */
MetadataExtractor getMetadataExtractor();
/**
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractorFactory.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractorFactory.java
index f407ffeb62..64c1612fe4 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractorFactory.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/OOXMLExtractorFactory.java
@@ -18,27 +18,18 @@ package org.apache.tika.parser.microsoft.ooxml;
import java.io.IOException;
import java.util.Locale;
+import java.util.Set;
-import org.apache.poi.extractor.ExtractorFactory;
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.extractor.POIXMLExtractorFactory;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.util.LocaleUtil;
-import org.apache.poi.xslf.extractor.XSLFExtractor;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFRelation;
-import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor;
-import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
+import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRelation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
@@ -51,9 +42,7 @@ import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.EmptyParser;
import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
import org.apache.tika.parser.microsoft.ooxml.xps.XPSExtractorDecorator;
-import org.apache.tika.parser.microsoft.ooxml.xps.XPSTextExtractor;
import org.apache.tika.parser.microsoft.ooxml.xslf.XSLFEventBasedPowerPointExtractor;
import org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor;
@@ -64,21 +53,22 @@ import org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor;
*/
public class OOXMLExtractorFactory {
- private static final Logger LOG = LoggerFactory.getLogger(OOXMLExtractorFactory.class);
- private static final int MAX_BUFFER_LENGTH = 1000000;
- private static POIXMLExtractorFactory EXTRACTOR_FACTORY = new POIXMLExtractorFactory();
+ private static final String OFFICE_DOCUMENT_REL =
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+ private static final String STRICT_OFFICE_DOCUMENT_REL =
+ "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
-
- //TODO find what happened to SUPPORTED_TYPES
- private static XSLFRelation[] XSLF_RELATIONS = new XSLFRelation[] {
+ private static final XSLFRelation[] XSLF_RELATIONS = new XSLFRelation[]{
XSLFRelation.MAIN, XSLFRelation.MACRO, XSLFRelation.MACRO_TEMPLATE,
XSLFRelation.PRESENTATIONML,
XSLFRelation.PRESENTATIONML_TEMPLATE, XSLFRelation.PRESENTATION_MACRO
};
- static {
- ExtractorFactory.setAllThreadsPreferEventExtractors(true);
- }
+ private static final XSSFRelation[] XSSF_RELATIONS = new XSSFRelation[]{
+ XSSFRelation.WORKBOOK, XSSFRelation.MACROS_WORKBOOK,
+ XSSFRelation.TEMPLATE_WORKBOOK, XSSFRelation.MACRO_TEMPLATE_WORKBOOK,
+ XSSFRelation.MACRO_ADDIN_WORKBOOK
+ };
public static void parse(TikaInputStream tis, ContentHandler baseHandler, Metadata metadata,
ParseContext context) throws IOException, SAXException, TikaException {
@@ -88,15 +78,9 @@ public class OOXMLExtractorFactory {
try {
OOXMLExtractor extractor = null;
- // Locate or Open the OPCPackage for the file
- // Detector should have prepared OPCPackageWrapper if salvaging was needed
if (tis.getOpenContainer() instanceof OPCPackageWrapper) {
pkg = ((OPCPackageWrapper) tis.getOpenContainer()).getOPCPackage();
} else {
- // POI 5.x can throw InvalidOperationException (a RuntimeException
- // extending OpenXML4JRuntimeException) for truncated/corrupt zip files.
- // The detector should have salvaged if needed, but catch broadly here
- // as a safety net.
try {
pkg = OPCPackage.open(tis.getPath().toString(), PackageAccess.READ);
} catch (RuntimeException e) {
@@ -119,79 +103,89 @@ public class OOXMLExtractorFactory {
type = MediaType.parse(mediaTypeString);
}
if (type != null && OOXMLParser.UNSUPPORTED_OOXML_TYPES.contains(type)) {
- // Not a supported type, delegate to Empty Parser
EmptyParser.INSTANCE.parse(tis, baseHandler, metadata, context);
return;
}
if (type == null || !OOXMLParser.SUPPORTED_TYPES.contains(type)) {
- // Get the type, and ensure it's one we handle
type = OPCPackageDetector.detectOfficeOpenXML(pkg);
}
if (type == null || OOXMLParser.UNSUPPORTED_OOXML_TYPES.contains(type)) {
- // Not a supported type, delegate to Empty Parser
EmptyParser.INSTANCE.parse(tis, baseHandler, metadata, context);
return;
}
metadata.set(Metadata.CONTENT_TYPE, type.toString());
- // Have the appropriate OOXML text extractor picked
- POIXMLTextExtractor poiExtractor = null;
- // This has already been set by OOXMLParser's call to configure()
- // We can rely on this being non-null.
- OfficeParserConfig config = context.get(OfficeParserConfig.class);
- if (config.isUseSAXDocxExtractor()) {
- poiExtractor = trySXWPF(pkg);
- }
- if (poiExtractor == null) {
- poiExtractor = tryXSLF(pkg, config.isUseSAXPptxExtractor());
- }
- if (type.equals(OOXMLParser.XPS)) {
- poiExtractor = new XPSTextExtractor(pkg);
- }
- if (poiExtractor == null) {
- poiExtractor = EXTRACTOR_FACTORY.create(pkg);
+ // Detect format and create the appropriate extractor
+ String coreContentType = getCorePartContentType(pkg);
+
+ if (isVisioType(type)) {
+ extractor = new VSDXExtractorDecorator(context, pkg);
+ } else if (type.equals(OOXMLParser.XPS)) {
+ extractor = new XPSExtractorDecorator(context, pkg);
+ } else if (coreContentType != null) {
+ // Try DOCX
+ for (XWPFRelation relation : XWPFWordExtractor.SUPPORTED_TYPES) {
+ if (coreContentType.equals(relation.getContentType())) {
+ XWPFEventBasedWordExtractor wordExtractor =
+ new XWPFEventBasedWordExtractor(pkg);
+ extractor = new SXWPFWordExtractorDecorator(metadata, context,
+ wordExtractor);
+ metadata.add(TikaCoreProperties.TIKA_PARSED_BY,
+ XWPFEventBasedWordExtractor.class.getCanonicalName());
+ break;
+ }
+ }
+
+ // Try PPTX
+ if (extractor == null) {
+ for (XSLFRelation relation : XSLF_RELATIONS) {
+ if (relation.getContentType().equals(coreContentType)) {
+ XSLFEventBasedPowerPointExtractor pptExtractor =
+ new XSLFEventBasedPowerPointExtractor(pkg);
+ extractor = new SXSLFPowerPointExtractorDecorator(metadata, context,
+ pptExtractor);
+ metadata.add(TikaCoreProperties.TIKA_PARSED_BY,
+ XSLFEventBasedPowerPointExtractor.class.getCanonicalName());
+ break;
+ }
+ }
+ if (extractor == null &&
+ XSLFRelation.THEME_MANAGER.getContentType().equals(coreContentType)) {
+ XSLFEventBasedPowerPointExtractor pptExtractor =
+ new XSLFEventBasedPowerPointExtractor(pkg);
+ extractor = new SXSLFPowerPointExtractorDecorator(metadata, context,
+ pptExtractor);
+ metadata.add(TikaCoreProperties.TIKA_PARSED_BY,
+ XSLFEventBasedPowerPointExtractor.class.getCanonicalName());
+ }
+ }
+
+ // Try XLSB
+ if (extractor == null &&
+ XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType()
+ .equals(coreContentType)) {
+ extractor = new XSSFBExcelExtractorDecorator(context, pkg, locale);
+ }
+
+ // Try XLSX
+ if (extractor == null) {
+ for (XSSFRelation relation : XSSF_RELATIONS) {
+ if (relation.getContentType().equals(coreContentType)) {
+ extractor = new XSSFExcelExtractorDecorator(context, pkg, locale);
+ break;
+ }
+ }
+ }
}
- POIXMLDocument document = poiExtractor.getDocument();
- if (poiExtractor instanceof XSSFBEventBasedExcelExtractor) {
- extractor = new XSSFBExcelExtractorDecorator(context, poiExtractor, locale);
- } else if (poiExtractor instanceof XSSFEventBasedExcelExtractor) {
- extractor = new XSSFExcelExtractorDecorator(context, poiExtractor, locale);
- } else if (poiExtractor instanceof XWPFEventBasedWordExtractor) {
- extractor = new SXWPFWordExtractorDecorator(metadata, context,
- (XWPFEventBasedWordExtractor) poiExtractor);
- metadata.add(TikaCoreProperties.TIKA_PARSED_BY,
- XWPFEventBasedWordExtractor.class.getCanonicalName());
- } else if (poiExtractor instanceof XSLFEventBasedPowerPointExtractor) {
- extractor = new SXSLFPowerPointExtractorDecorator(metadata, context,
- (XSLFEventBasedPowerPointExtractor) poiExtractor);
- metadata.add(TikaCoreProperties.TIKA_PARSED_BY,
- XSLFEventBasedPowerPointExtractor.class.getCanonicalName());
- } else if (poiExtractor instanceof XPSTextExtractor) {
- extractor = new XPSExtractorDecorator(context, poiExtractor);
- } else if (document == null) {
+ if (extractor == null) {
throw new TikaException(
- "Expecting UserModel based POI OOXML extractor with a document, but none" +
- " found. " +
- "The extractor returned was a " + poiExtractor);
- } else if (document instanceof XMLSlideShow) {
- extractor = new XSLFPowerPointExtractorDecorator(metadata, context,
- (org.apache.poi.xslf.extractor.XSLFExtractor) poiExtractor);
- } else if (document instanceof XWPFDocument) {
- extractor = new XWPFWordExtractorDecorator(metadata, context,
- (XWPFWordExtractor) poiExtractor);
- } else {
- extractor = new POIXMLTextExtractorDecorator(context, poiExtractor);
+ "No OOXML extractor found for content type: " + coreContentType);
}
-
- // Get the bulk of the metadata first, so that it's accessible during
- // parsing if desired by the client (see TIKA-1109)
extractor.getMetadataExtractor().extract(metadata);
-
- // Extract the text, along with any in-document metadata
extractor.getXHTML(baseHandler, metadata, context);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null &&
@@ -208,70 +202,33 @@ public class OOXMLExtractorFactory {
}
}
- private static POIXMLTextExtractor trySXWPF(OPCPackage pkg)
- throws TikaException, OpenXML4JException, IOException {
- PackageRelationshipCollection packageRelationshipCollection = pkg.getRelationshipsByType(
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
- if (packageRelationshipCollection.size() == 0) {
- packageRelationshipCollection = pkg.getRelationshipsByType(
- "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument");
- }
-
- if (packageRelationshipCollection.size() == 0) {
- return null;
- }
- PackagePart corePart = pkg.getPart(packageRelationshipCollection.getRelationship(0));
- if (corePart == null) {
- throw new TikaException("Couldn't find core part.");
- }
- String targetContentType = corePart.getContentType();
- for (XWPFRelation relation : XWPFWordExtractor.SUPPORTED_TYPES) {
- if (targetContentType.equals(relation.getContentType())) {
- return new XWPFEventBasedWordExtractor(pkg);
- }
- }
- return null;
+ private static final Set<String> VISIO_SUBTYPES = Set.of(
+ "vnd.ms-visio.drawing",
+ "vnd.ms-visio.drawing.macroenabled.12",
+ "vnd.ms-visio.stencil",
+ "vnd.ms-visio.stencil.macroenabled.12",
+ "vnd.ms-visio.template",
+ "vnd.ms-visio.template.macroenabled.12"
+ );
+
+ private static boolean isVisioType(MediaType type) {
+ return type != null && VISIO_SUBTYPES.contains(type.getSubtype());
}
- private static POIXMLTextExtractor tryXSLF(OPCPackage pkg, boolean eventBased)
- throws TikaException, OpenXML4JException, IOException {
-
- PackageRelationshipCollection packageRelationshipCollection = pkg.getRelationshipsByType(
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
- if (packageRelationshipCollection.size() == 0) {
- packageRelationshipCollection = pkg.getRelationshipsByType(
- "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument");
- }
-
- if (packageRelationshipCollection.size() == 0) {
- return null;
- }
- PackagePart corePart = pkg.getPart(packageRelationshipCollection.getRelationship(0));
- if (corePart == null) {
- throw new TikaException("Couldn't find core part");
- }
- String targetContentType = corePart.getContentType();
-
- for (int i = 0; i < XSLF_RELATIONS.length; i++) {
- XSLFRelation xslfRelation = XSLF_RELATIONS[i];
- if (xslfRelation.getContentType().equals(targetContentType)) {
- if (eventBased) {
- return new XSLFEventBasedPowerPointExtractor(pkg);
- } else {
- return new XSLFExtractor(new XMLSlideShow(pkg));
- }
+ private static String getCorePartContentType(OPCPackage pkg) {
+ try {
+ PackageRelationshipCollection rels =
+ pkg.getRelationshipsByType(OFFICE_DOCUMENT_REL);
+ if (rels.size() == 0) {
+ rels = pkg.getRelationshipsByType(STRICT_OFFICE_DOCUMENT_REL);
}
- }
-
- if (XSLFRelation.THEME_MANAGER.getContentType().equals(targetContentType)) {
- if (eventBased) {
- return new XSLFEventBasedPowerPointExtractor(pkg);
- } else {
- return new XSLFExtractor(new XMLSlideShow(pkg));
+ if (rels.size() == 0) {
+ return null;
}
+ PackagePart corePart = pkg.getPart(rels.getRelationship(0));
+ return corePart != null ? corePart.getContentType() : null;
+ } catch (Exception e) {
+ return null;
}
- return null;
}
-
-
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/POIXMLTextExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/POIXMLTextExtractorDecorator.java
deleted file mode 100644
index be3c78f3ae..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/POIXMLTextExtractorDecorator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
-import org.xml.sax.SAXException;
-
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.sax.XHTMLContentHandler;
-
-public class POIXMLTextExtractorDecorator extends AbstractOOXMLExtractor {
-
- public POIXMLTextExtractorDecorator(ParseContext context, POIXMLTextExtractor extractor) {
- super(context, extractor);
-
- if (extractor instanceof XSSFExcelExtractor) {
- ((XSSFExcelExtractor) extractor)
- .setIncludeTextBoxes(config.isIncludeShapeBasedContent());
- }
- }
-
- @Override
- protected void buildXHTML(XHTMLContentHandler xhtml) throws SAXException {
- // extract document content as a single string (not structured)
- xhtml.element("p", extractor.getText());
- }
-
- @Override
- protected List<PackagePart> getMainDocumentParts() {
- return new ArrayList<>();
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SAXBasedMetadataExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SAXBasedMetadataExtractor.java
index 7307e35437..632eb0c6c8 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SAXBasedMetadataExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SAXBasedMetadataExtractor.java
@@ -60,7 +60,6 @@ class SAXBasedMetadataExtractor extends MetadataExtractor {
private final ParseContext parseContext;
SAXBasedMetadataExtractor(OPCPackage opcPackage, ParseContext parseContext) {
- super(null);
this.opcPackage = opcPackage;
this.parseContext = parseContext;
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
index 7d8030afad..43c1e7d8b7 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXSLFPowerPointExtractorDecorator.java
@@ -25,7 +25,6 @@ import java.util.Map;
import java.util.zip.ZipException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
@@ -68,7 +67,6 @@ public class SXSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
//TODO: what else
};
- private final OPCPackage opcPackage;
private final ParseContext context;
private final Metadata metadata;
private final CommentAuthors commentAuthors = new CommentAuthors();
@@ -76,10 +74,9 @@ public class SXSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
public SXSLFPowerPointExtractorDecorator(Metadata metadata, ParseContext context,
XSLFEventBasedPowerPointExtractor extractor) {
- super(context, extractor);
+ super(context, extractor.getPackage());
this.metadata = metadata;
this.context = context;
- this.opcPackage = extractor.getPackage();
for (String contentType : MAIN_STORY_PART_RELATIONS) {
List<PackagePart> pps = opcPackage.getPartsByContentType(contentType);
if (pps.size() > 0) {
@@ -87,12 +84,6 @@ public class SXSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
break;
}
}
- //if mainDocument == null, throw exception
- }
-
- @Override
- public MetadataExtractor getMetadataExtractor() {
- return new SAXBasedMetadataExtractor(opcPackage, context);
}
/**
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXWPFWordExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXWPFWordExtractorDecorator.java
index 88c7aaa0f7..d990e6f96a 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXWPFWordExtractorDecorator.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/SXWPFWordExtractorDecorator.java
@@ -27,7 +27,6 @@ import java.util.Set;
import java.util.zip.ZipException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
@@ -96,7 +95,6 @@ public class SXWPFWordExtractorDecorator extends AbstractOOXMLExtractor {
};
- private final OPCPackage opcPackage;
private final ParseContext context;
private final Metadata metadata;
private final Map<String, EmbeddedPartMetadata> embeddedPartMetadataMap = new HashMap<>();
@@ -104,15 +102,9 @@ public class SXWPFWordExtractorDecorator extends AbstractOOXMLExtractor {
public SXWPFWordExtractorDecorator(Metadata metadata, ParseContext context,
XWPFEventBasedWordExtractor extractor) {
- super(context, extractor);
+ super(context, extractor.getPackage());
this.metadata = metadata;
this.context = context;
- this.opcPackage = extractor.getPackage();
- }
-
- @Override
- public MetadataExtractor getMetadataExtractor() {
- return new SAXBasedMetadataExtractor(opcPackage, context);
}
@Override
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBCommentsTable.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBCommentsTable.java
new file mode 100644
index 0000000000..79a968a0ba
--- /dev/null
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBCommentsTable.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.parser.microsoft.ooxml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.xssf.binary.XSSFBParser;
+import org.apache.poi.xssf.binary.XSSFBRecordType;
+import org.apache.poi.xssf.binary.XSSFBUtils;
+import org.xml.sax.SAXException;
+
+import org.apache.tika.sax.XHTMLContentHandler;
+
+/**
+ * Replacement for POI's {@code XSSFBCommentsTable} that does not depend on
+ * {@code XSSFBComment}/{@code XSSFBRichTextString}/{@code XSSFRichTextString}
+ * (which pull in poi-ooxml-lite / xmlbeans via {@code CTRst}).
+ * <p>
+ * Stores comments as plain author + text strings.
+ */
+class TikaXSSFBCommentsTable extends XSSFBParser {
+
+ private final Map<CellAddress, CommentEntry> comments = new TreeMap<>();
+ private final List<String> authors = new ArrayList<>();
+
+ private int authorId = -1;
+ private int cellRow = -1;
+ private int cellCol = -1;
+ private String commentText;
+ private final StringBuilder buffer = new StringBuilder();
+
+ TikaXSSFBCommentsTable(InputStream is) throws IOException {
+ super(is);
+ parse();
+ }
+
+ @Override
+ public void handleRecord(int id, byte[] data) {
+ XSSFBRecordType recordType = XSSFBRecordType.lookup(id);
+ switch (recordType) {
+ case BrtBeginComment:
+ authorId = (int) LittleEndian.getUInt(data, 0);
+ // cell range: firstRow at offset 4, firstCol at offset 12
+ cellRow = (int) LittleEndian.getUInt(data, LittleEndianConsts.INT_SIZE);
+ cellCol = (int) LittleEndian.getUInt(data,
+ LittleEndianConsts.INT_SIZE + 2 * LittleEndianConsts.INT_SIZE);
+ break;
+ case BrtCommentText:
+ buffer.setLength(0);
+ XSSFBUtils.readXLWideString(data, 1, buffer);
+ commentText = buffer.toString();
+ break;
+ case BrtEndComment:
+ CellAddress addr = new CellAddress(cellRow, cellCol);
+ String author = (authorId >= 0 && authorId < authors.size())
+ ? authors.get(authorId) : "";
+ comments.put(addr, new CommentEntry(author, commentText));
+ authorId = -1;
+ cellRow = -1;
+ cellCol = -1;
+ commentText = null;
+ break;
+ case BrtCommentAuthor:
+ buffer.setLength(0);
+ XSSFBUtils.readXLWideString(data, 0, buffer);
+ authors.add(buffer.toString());
+ break;
+ default:
+ break;
+ }
+ }
+
+ CommentEntry get(CellAddress cellAddress) {
+ return cellAddress == null ? null : comments.get(cellAddress);
+ }
+
+ boolean hasComments() {
+ return !comments.isEmpty();
+ }
+
+ /**
+ * Emits all comments as cell content. Called after sheet processing
+ * since we bypass POI's built-in comment handling.
+ */
+ void emitAllComments(XHTMLContentHandler xhtml) throws SAXException {
+ for (Map.Entry<CellAddress, CommentEntry> entry : comments.entrySet()) {
+ CommentEntry comment = entry.getValue();
+ xhtml.startElement("p", "class", "cell-comment");
+ String author = comment.getAuthor();
+ if (author != null && !author.isEmpty()) {
+ xhtml.characters(author + ": ");
+ }
+ xhtml.characters(comment.getText());
+ xhtml.endElement("p");
+ }
+ }
+
+ static class CommentEntry {
+ private final String author;
+ private final String text;
+
+ CommentEntry(String author, String text) {
+ this.author = author;
+ this.text = text;
+ }
+
+ String getAuthor() {
+ return author;
+ }
+
+ String getText() {
+ return text;
+ }
+ }
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBSharedStringsTable.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBSharedStringsTable.java
new file mode 100644
index 0000000000..6e1ec853d5
--- /dev/null
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/TikaXSSFBSharedStringsTable.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.parser.microsoft.ooxml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.xssf.binary.XSSFBParser;
+import org.apache.poi.xssf.binary.XSSFBRecordType;
+import org.apache.poi.xssf.binary.XSSFBUtils;
+import org.apache.poi.xssf.model.SharedStrings;
+
+/**
+ * Replacement for POI's {@code XSSFBSharedStringsTable} that does not depend on
+ * {@code XSSFRichTextString} (which pulls in poi-ooxml-lite / xmlbeans via {@code CTRst}).
+ * <p>
+ * The binary parsing logic is identical to POI's implementation; only
+ * {@link #getItemAt(int)} is changed to return a lightweight {@link RichTextString}
+ * wrapper instead of {@code XSSFRichTextString}.
+ */
+class TikaXSSFBSharedStringsTable implements SharedStrings {
+
+ private static final String SHARED_STRINGS_BINARY_CT =
+ "application/vnd.ms-excel.sharedStrings";
+
+ private int count;
+ private int uniqueCount;
+ private final List<String> strings = new ArrayList<>();
+
+ TikaXSSFBSharedStringsTable(OPCPackage pkg) throws IOException {
+ ArrayList<PackagePart> parts =
+ pkg.getPartsByContentType(SHARED_STRINGS_BINARY_CT);
+ if (!parts.isEmpty()) {
+ PackagePart sstPart = parts.get(0);
+ try (InputStream stream = sstPart.getInputStream()) {
+ readFrom(stream);
+ }
+ }
+ }
+
+ private void readFrom(InputStream inputStream) throws IOException {
+ new SSTBinaryReader(inputStream).parse();
+ }
+
+ @Override
+ public RichTextString getItemAt(int idx) {
+ return new PlainRichTextString(strings.get(idx));
+ }
+
+ @Override
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public int getUniqueCount() {
+ return uniqueCount;
+ }
+
+ private class SSTBinaryReader extends XSSFBParser {
+
+ SSTBinaryReader(InputStream is) {
+ super(is);
+ }
+
+ @Override
+ public void handleRecord(int recordType, byte[] data) {
+ XSSFBRecordType type = XSSFBRecordType.lookup(recordType);
+ switch (type) {
+ case BrtSstItem:
+ // Inline XSSFBRichStr.build() logic — that class is package-private in POI
+ StringBuilder sb = new StringBuilder();
+ XSSFBUtils.readXLWideString(data, 1, sb);
+ strings.add(sb.toString());
+ break;
+ case BrtBeginSst:
+ count = (int) LittleEndian.getUInt(data, 0);
+ uniqueCount = (int) LittleEndian.getUInt(data, 4);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Minimal {@link RichTextString} that just wraps a plain string,
+ * avoiding the xmlbeans dependency in {@code XSSFRichTextString}.
+ */
+ private static class PlainRichTextString implements RichTextString {
+
+ private final String text;
+
+ PlainRichTextString(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String getString() {
+ return text;
+ }
+
+ @Override
+ public int length() {
+ return text == null ? 0 : text.length();
+ }
+
+ @Override
+ public int numFormattingRuns() {
+ return 0;
+ }
+
+ @Override
+ public int getIndexOfFormattingRun(int index) {
+ return 0;
+ }
+
+ @Override
+ public void applyFont(int startIndex, int endIndex, short fontIndex) {
+ }
+
+ @Override
+ public void applyFont(int startIndex, int endIndex, Font font) {
+ }
+
+ @Override
+ public void applyFont(Font font) {
+ }
+
+ @Override
+ public void clearFormatting() {
+ }
+
+ @Override
+ public void applyFont(short fontIndex) {
+ }
+ }
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/VSDXExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/VSDXExtractorDecorator.java
new file mode 100644
index 0000000000..7e671057c2
--- /dev/null
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/VSDXExtractorDecorator.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.parser.microsoft.ooxml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.sax.XHTMLContentHandler;
+import org.apache.tika.utils.XMLReaderUtils;
+
+/**
+ * SAX-based extractor for Visio OOXML (.vsdx) files.
+ * Extracts text from {@code <Text>} elements inside shapes on each page.
+ */
+public class VSDXExtractorDecorator extends AbstractOOXMLExtractor {
+
+ private static final String VISIO_DOCUMENT_REL =
+ "http://schemas.microsoft.com/visio/2010/relationships/document";
+ private static final String VISIO_PAGES_REL =
+ "http://schemas.microsoft.com/visio/2010/relationships/pages";
+ private static final String VISIO_PAGE_REL =
+ "http://schemas.microsoft.com/visio/2010/relationships/page";
+
+ private final ParseContext context;
+
+ public VSDXExtractorDecorator(ParseContext context, OPCPackage pkg) {
+ super(context, pkg);
+ this.context = context;
+ }
+
+ @Override
+ protected void buildXHTML(XHTMLContentHandler xhtml)
+ throws SAXException, IOException {
+ try {
+ List<PackagePart> pageParts = getPageParts();
+ for (PackagePart pagePart : pageParts) {
+ xhtml.startElement("div", "class", "page");
+ try (InputStream is = pagePart.getInputStream()) {
+ XMLReaderUtils.parseSAX(is, new VisioPageHandler(xhtml), context);
+ } catch (TikaException e) {
+ throw new SAXException(e);
+ }
+ xhtml.endElement("div");
+ }
+ } catch (InvalidFormatException e) {
+ throw new SAXException("Error reading VSDX pages", e);
+ }
+ }
+
+ private List<PackagePart> getPageParts() throws InvalidFormatException {
+ // Root -> visio/document.xml
+ PackagePart documentPart = getRelatedPart(opcPackage, VISIO_DOCUMENT_REL);
+ if (documentPart == null) {
+ return Collections.emptyList();
+ }
+
+ // document.xml -> pages/pages.xml
+ PackagePart pagesPart = getRelatedPart(documentPart, VISIO_PAGES_REL);
+ if (pagesPart == null) {
+ return Collections.emptyList();
+ }
+
+ // pages.xml -> page1.xml, page2.xml, ...
+ List<PackagePart> pageParts = new ArrayList<>();
+ PackageRelationshipCollection pageRels =
+ pagesPart.getRelationshipsByType(VISIO_PAGE_REL);
+ for (PackageRelationship rel : pageRels) {
+ PackagePart pagePart = pagesPart.getRelatedPart(rel);
+ if (pagePart != null) {
+ pageParts.add(pagePart);
+ }
+ }
+ return pageParts;
+ }
+
+ private PackagePart getRelatedPart(OPCPackage pkg, String relType)
+ throws InvalidFormatException {
+ PackageRelationshipCollection rels = pkg.getRelationshipsByType(relType);
+ if (rels.isEmpty()) {
+ return null;
+ }
+ return pkg.getPart(rels.getRelationship(0));
+ }
+
+ private PackagePart getRelatedPart(PackagePart part, String relType)
+ throws InvalidFormatException {
+ PackageRelationshipCollection rels = part.getRelationshipsByType(relType);
+ if (rels.isEmpty()) {
+ return null;
+ }
+ return part.getRelatedPart(rels.getRelationship(0));
+ }
+
+ @Override
+ protected List<PackagePart> getMainDocumentParts() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * SAX handler for Visio page XML. Extracts text from {@code <Text>}
+ * elements inside {@code <Shape>} elements.
+ */
+ private static class VisioPageHandler extends DefaultHandler {
+
+ private static final String VISIO_NS =
+ "http://schemas.microsoft.com/office/visio/2012/main";
+
+ private final XHTMLContentHandler xhtml;
+ private boolean inText;
+ private final StringBuilder textBuffer = new StringBuilder();
+
+ VisioPageHandler(XHTMLContentHandler xhtml) {
+ this.xhtml = xhtml;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts) {
+ if ("Text".equals(localName) && VISIO_NS.equals(uri)) {
+ inText = true;
+ textBuffer.setLength(0);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+ if ("Text".equals(localName) && VISIO_NS.equals(uri)) {
+ inText = false;
+ String text = textBuffer.toString().trim();
+ if (!text.isEmpty()) {
+ xhtml.startElement("p");
+ xhtml.characters(text);
+ xhtml.endElement("p");
+ }
+ }
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) {
+ if (inText) {
+ textBuffer.append(ch, start, length);
+ }
+ }
+ }
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java
deleted file mode 100644
index fb9876fce8..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSLFPowerPointExtractorDecorator.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.xml.namespace.QName;
-
-import org.apache.poi.common.usermodel.Hyperlink;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.openxml4j.opc.PackagePartName;
-import org.apache.poi.openxml4j.opc.PackageRelationship;
-import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
-import org.apache.poi.openxml4j.opc.PackagingURIHelper;
-import org.apache.poi.openxml4j.opc.TargetMode;
-import org.apache.poi.sl.usermodel.Placeholder;
-import org.apache.poi.xslf.extractor.XSLFExtractor;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFComment;
-import org.apache.poi.xslf.usermodel.XSLFCommentAuthors;
-import org.apache.poi.xslf.usermodel.XSLFGraphicFrame;
-import org.apache.poi.xslf.usermodel.XSLFGroupShape;
-import org.apache.poi.xslf.usermodel.XSLFHyperlink;
-import org.apache.poi.xslf.usermodel.XSLFNotes;
-import org.apache.poi.xslf.usermodel.XSLFNotesMaster;
-import org.apache.poi.xslf.usermodel.XSLFPictureShape;
-import org.apache.poi.xslf.usermodel.XSLFRelation;
-import org.apache.poi.xslf.usermodel.XSLFShape;
-import org.apache.poi.xslf.usermodel.XSLFSheet;
-import org.apache.poi.xslf.usermodel.XSLFSlide;
-import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
-import org.apache.poi.xslf.usermodel.XSLFSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFTable;
-import org.apache.poi.xslf.usermodel.XSLFTableCell;
-import org.apache.poi.xslf.usermodel.XSLFTableRow;
-import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
-import org.apache.poi.xslf.usermodel.XSLFTextRun;
-import org.apache.poi.xslf.usermodel.XSLFTextShape;
-import org.apache.xmlbeans.XmlObject;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthor;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTCommentAuthorList;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.tika.exception.TikaException;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.sax.XHTMLContentHandler;
-import org.apache.tika.utils.StringUtils;
-
-public class XSLFPowerPointExtractorDecorator extends AbstractOOXMLExtractor {
-
- private final static String HANDOUT_MASTER =
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/handoutMaster";
-
- private Metadata metadata;
-
- public XSLFPowerPointExtractorDecorator(Metadata metadata, ParseContext context,
- XSLFExtractor extractor) {
- super(context, extractor);
- this.metadata = metadata;
- }
-
-
- /**
- * @see XSLFExtractor#getText()
- */
- protected void buildXHTML(XHTMLContentHandler xhtml) throws SAXException, IOException {
- XMLSlideShow slideShow = (XMLSlideShow) extractor.getDocument();
- handleCommentAuthors(slideShow);
-
- List<XSLFSlide> slides = slideShow.getSlides();
- AtomicInteger hiddenSlideCounter = new AtomicInteger(0);
- for (XSLFSlide slide : slides) {
- handleSlide(slide, xhtml, hiddenSlideCounter);
- }
- if (hiddenSlideCounter.get() > 0) {
- metadata.set(Office.HAS_HIDDEN_SLIDES, true);
- metadata.set(Office.NUM_HIDDEN_SLIDES, hiddenSlideCounter.get());
- }
- }
-
- private void handleSlide(XSLFSlide slide, XHTMLContentHandler xhtml, AtomicInteger hiddenSlideCounter) throws SAXException {
- String slideDesc;
- if (slide.getPackagePart() != null && slide.getPackagePart().getPartName() != null) {
- slideDesc = getJustFileName(slide.getPackagePart().getPartName().toString());
- slideDesc += "_";
- } else {
- slideDesc = null;
- }
-
- if (slide.isHidden()) {
- hiddenSlideCounter.incrementAndGet();
- }
-
- // slide content
- xhtml.startElement("div", "class", "slide-content");
- extractContent(slide.getShapes(), false, xhtml, slideDesc);
- xhtml.endElement("div");
-
- if (config.isIncludeSlideMasterContent()) {
- // 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);
- }
- if (config.isIncludeSlideNotes()) {
- // 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");
- }
- }
-
- // comments (if present)
- List<XSLFComment> comments = slide.getComments();
- if (comments != null) {
- StringBuilder authorStringBuilder = new StringBuilder();
- for (XSLFComment comment : comments) {
- authorStringBuilder.setLength(0);
- xhtml.startElement("p", "class", "slide-comment");
- if (comment.getAuthor() != null) {
- authorStringBuilder.append(comment.getAuthor());
- }
- if (comment.getAuthorInitials() != null) {
- if (authorStringBuilder.length() > 0) {
- authorStringBuilder.append(" ");
- }
- authorStringBuilder.append("(").append(comment.getAuthorInitials()).append(")");
- }
- if (comment.getText() != null && authorStringBuilder.length() > 0) {
- authorStringBuilder.append(" - ");
- }
- if (authorStringBuilder.length() > 0) {
- xhtml.startElement("b");
- xhtml.characters(authorStringBuilder.toString());
- xhtml.endElement("b");
- }
-
- xhtml.characters(comment.getText());
- xhtml.endElement("p");
- }
- }
- //now dump diagram data
- handleGeneralTextContainingPart(RELATION_DIAGRAM_DATA, "diagram-data",
- slide.getPackagePart(), metadata,
- new OOXMLWordAndPowerPointTextHandler(new OOXMLTikaBodyPartHandler(xhtml),
- new HashMap<>()//empty
- ));
- //now dump chart data
- handleGeneralTextContainingPart(XSLFRelation.CHART.getRelation(), "chart",
- slide.getPackagePart(), metadata,
- new OOXMLWordAndPowerPointTextHandler(new OOXMLTikaBodyPartHandler(xhtml),
- new HashMap<>()//empty
- ));
-
- CTSlide ctSlide = slide.getXmlObject();
- if (ctSlide.isSetTiming()) {
- //perhaps require more, like: ctSlide.getTiming()?.getTnLst()?.getParArray()?.length
- metadata.set(Office.HAS_ANIMATIONS, true);
- }
- }
-
- private void handleCommentAuthors(XMLSlideShow slideShow) {
- XSLFCommentAuthors commentAuthors = slideShow.getCommentAuthors();
- if (commentAuthors != null) {
- CTCommentAuthorList ctAuthorList = commentAuthors.getCTCommentAuthorsList();
- CTCommentAuthor[] ctAuthorArray = ctAuthorList.getCmAuthorArray();
- if (ctAuthorArray != null) {
- Set<String> names = new HashSet<>();
- for (CTCommentAuthor ctCommentAuthor : ctAuthorArray) {
- String n = ctCommentAuthor.getName();
- if (StringUtils.isBlank(n) || names.contains(n)) {
- continue;
- }
- metadata.add(Office.COMMENT_PERSONS, n);
- names.add(n);
- }
- }
- }
- }
-
- 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();
- if (skipPlaceholders && ph != null) {
- continue;
- }
- boolean inHyperlink = false;
- for (XSLFTextParagraph p : txt.getTextParagraphs()) {
- xhtml.startElement("p");
- if (!config.isIncludeHeadersAndFooters() && 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
- //external and not footnote refs via the current hack
- Hyperlink hyperlink = run.getHyperlink();
-
- if (hyperlink != null && hyperlink.getAddress() != null &&
- !hyperlink.getAddress().contains("#_ftn")) {
- xhtml.startElement("a", "href", hyperlink.getAddress());
- inHyperlink = true;
- }
- xhtml.characters(run.getRawText());
- if (inHyperlink == true) {
- xhtml.endElement("a");
- }
- inHyperlink = false;
- }
- xhtml.endElement("p");
- }
- } else if (sh instanceof XSLFGroupShape) {
- // recurse into groups of shapes
- XSLFGroupShape group = (XSLFGroupShape) sh;
- extractContent(group.getShapes(), skipPlaceholders, xhtml, slideDesc);
- } else if (sh instanceof XSLFTable) {
- //unlike tables in Word, ppt/x can't have recursive tables...I don't think
- extractTable((XSLFTable) sh, xhtml);
- } else if (sh instanceof XSLFGraphicFrame) {
- XSLFGraphicFrame frame = (XSLFGraphicFrame) sh;
- XmlObject[] sp = frame.getXmlObject().selectPath(
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:oleObj");
- if (sp != null) {
- for (XmlObject emb : sp) {
- XmlObject relIDAtt = emb.selectAttribute(new QName(
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
- "id"));
- if (relIDAtt != null) {
- String relID = relIDAtt.getDomNode().getNodeValue();
- if (slideDesc != null) {
- relID = slideDesc + relID;
- }
- AttributesImpl attributes = new AttributesImpl();
- attributes.addAttribute("", "class", "class", "CDATA", "embedded");
- attributes.addAttribute("", "id", "id", "CDATA", relID);
- xhtml.startElement("div", attributes);
- xhtml.endElement("div");
- }
- }
- }
- } else if (sh instanceof XSLFPictureShape) {
- if (!skipPlaceholders && (sh.getXmlObject() instanceof CTPicture)) {
- CTPicture ctPic = ((CTPicture) sh.getXmlObject());
- if (ctPic.getBlipFill() != null && ctPic.getBlipFill().getBlip() != null) {
- String relID = ctPic.getBlipFill().getBlip().getEmbed();
- if (relID != null) {
- if (slideDesc != null) {
- relID = slideDesc + relID;
- }
- AttributesImpl attributes = new AttributesImpl();
- attributes.addAttribute("", "class", "class", "CDATA", "embedded");
- attributes.addAttribute("", "id", "id", "CDATA", relID);
- xhtml.startElement("div", attributes);
- xhtml.endElement("div");
- }
- }
- }
- }
- }
- }
-
- private void extractTable(XSLFTable tbl, XHTMLContentHandler xhtml) throws SAXException {
- xhtml.startElement("table");
- for (XSLFTableRow row : tbl) {
- xhtml.startElement("tr");
- for (XSLFTableCell c : row.getCells()) {
- xhtml.startElement("td");
- //TODO: Need to wait for fix in POI to test for hyperlink first
- //shouldn't need to catch NPE...
- XSLFHyperlink hyperlink = null;
- try {
- hyperlink = c.getHyperlink();
- } catch (NullPointerException e) {
- //swallow
- }
- if (hyperlink != null && hyperlink.getAddress() != null) {
- xhtml.startElement("a", "href", hyperlink.getAddress());
- }
- xhtml.characters(c.getText());
- if (hyperlink != null && hyperlink.getAddress() != null) {
- xhtml.endElement("a");
- }
- xhtml.endElement("td");
- }
- xhtml.endElement("tr");
- }
- xhtml.endElement("table");
-
- }
-
- /**
- * In PowerPoint files, slides have things embedded in them,
- * and slide drawings which have the images
- */
- @Override
- protected List<PackagePart> getMainDocumentParts() throws TikaException {
- List<PackagePart> parts = new ArrayList<>();
- XSLFSlideShow document = null;
- try {
- document = new XSLFSlideShow(extractor.getPackage());
- } catch (Exception e) {
- throw new TikaException(e.getMessage()); // Shouldn't happen
- }
-
- CTSlideIdList ctSlideIdList = document.getSlideReferences();
- if (ctSlideIdList != null) {
- for (int i = 0; i < ctSlideIdList.sizeOfSldIdArray(); i++) {
- CTSlideIdListEntry ctSlide = ctSlideIdList.getSldIdArray(i);
- // Add the slide
- PackagePart slidePart;
- try {
- slidePart = document.getSlidePart(ctSlide);
- } catch (Exception e) {
- throw new TikaException("Broken OOXML file", e);
- }
- addSlideParts(slidePart, parts);
- }
- }
- //add full document to include macros
- parts.add(document.getPackagePart());
-
- for (String rel : new String[]{XSLFRelation.SLIDE_MASTER.getRelation(), HANDOUT_MASTER}) {
- try {
- PackageRelationshipCollection prc =
- document.getPackagePart().getRelationshipsByType(rel);
- for (int i = 0; i < prc.size(); i++) {
- PackagePart pp =
- document.getPackagePart().getRelatedPart(prc.getRelationship(i));
- if (pp != null) {
- parts.add(pp);
- }
- }
-
- } catch (InvalidFormatException e) {
- //log
- }
- }
-
- return parts;
- }
-
-
- private void addSlideParts(PackagePart slidePart, List<PackagePart> parts) {
-
- for (String relation : new String[]{XSLFRelation.VML_DRAWING.getRelation(),
- XSLFRelation.SLIDE_LAYOUT.getRelation(), XSLFRelation.NOTES_MASTER.getRelation(),
- XSLFRelation.NOTES.getRelation(), XSLFRelation.CHART.getRelation(),
- XSLFRelation.DIAGRAM_DRAWING.getRelation()}) {
- try {
- for (PackageRelationship packageRelationship : slidePart
- .getRelationshipsByType(relation)) {
- if (packageRelationship.getTargetMode() == TargetMode.INTERNAL) {
- PackagePartName relName = PackagingURIHelper
- .createPartName(packageRelationship.getTargetURI());
- parts.add(packageRelationship.getPackage().getPart(relName));
- }
- }
- } catch (InvalidFormatException e) {
- //swallow
- }
- }
- //and slide of course
- parts.add(slidePart);
-
- }
-
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFBExcelExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFBExcelExtractorDecorator.java
index 0db32f067a..d59ddd6528 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFBExcelExtractorDecorator.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFBExcelExtractorDecorator.java
@@ -20,17 +20,17 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.xssf.binary.XSSFBCommentsTable;
-import org.apache.poi.xssf.binary.XSSFBSharedStringsTable;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.xssf.binary.XSSFBSheetHandler;
import org.apache.poi.xssf.binary.XSSFBStylesTable;
import org.apache.poi.xssf.eventusermodel.XSSFBReader;
-import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
-import org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
@@ -43,17 +43,9 @@ import org.apache.tika.sax.XHTMLContentHandler;
public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
- public XSSFBExcelExtractorDecorator(ParseContext context, POIXMLTextExtractor extractor,
+ public XSSFBExcelExtractorDecorator(ParseContext context, OPCPackage pkg,
Locale locale) {
- super(context, extractor, locale);
- }
-
- @Override
- protected void configureExtractor(POIXMLTextExtractor extractor, Locale locale) {
- //need to override this because setFormulasNotResults is not yet available
- //for xlsb
- //((XSSFBEventBasedExcelExtractor)extractor).setFormulasNotResults(false);
- ((XSSFBEventBasedExcelExtractor) extractor).setLocale(locale);
+ super(context, pkg, locale);
}
@Override
@@ -67,15 +59,12 @@ public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
super.getXHTML(handler, metadata, context);
}
- /**
- * @see org.apache.poi.xssf.extractor.XSSFBEventBasedExcelExtractor#getText()
- */
@Override
protected void buildXHTML(XHTMLContentHandler xhtml)
throws SAXException, IOException {
- OPCPackage container = extractor.getPackage();
+ OPCPackage container = opcPackage;
- XSSFBSharedStringsTable strings;
+ TikaXSSFBSharedStringsTable strings;
XSSFBReader.SheetIterator iter;
XSSFBReader xssfReader;
XSSFBStylesTable styles;
@@ -87,7 +76,7 @@ public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
}
styles = xssfReader.getXSSFBStylesTable();
iter = (XSSFBReader.SheetIterator) xssfReader.getSheetsData();
- strings = new XSSFBSharedStringsTable(container);
+ strings = new TikaXSSFBSharedStringsTable(container);
} catch (OpenXML4JException e) {
throw new IOException(e);
}
@@ -99,24 +88,35 @@ public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
sheetParts.add(sheetPart);
SheetTextAsHTML sheetExtractor = new SheetTextAsHTML(config, xhtml);
- XSSFBCommentsTable comments = iter.getXSSFBSheetComments();
- // Start, and output the sheet name
+ // Parse comments with our own binary parser that avoids xmlbeans
+ TikaXSSFBCommentsTable tikaComments = parseBinaryComments(sheetPart);
+ if (tikaComments != null && tikaComments.hasComments()) {
+ metadata.set(Office.HAS_COMMENTS, true);
+ }
+
xhtml.startElement("div");
xhtml.element("h1", iter.getSheetName());
- // Extract the main sheet contents
xhtml.startElement("table");
xhtml.startElement("tbody");
- processSheet(sheetExtractor, comments, styles, strings, stream);
+ // Pass null for POI's comments table to avoid xmlbeans dependency.
+ // Comments are emitted separately after sheet processing.
+ XSSFBSheetHandler xssfbSheetHandler =
+ new XSSFBSheetHandler(stream, styles, null, strings,
+ sheetExtractor, formatter, false);
+ xssfbSheetHandler.parse();
xhtml.endElement("tbody");
xhtml.endElement("table");
- // Output any headers and footers
- // (Need to process the sheet to get them, so we can't
- // do the headers before the contents)
+ // Emit comments after the table (since we bypass POI's inline
+ // comment handling to avoid xmlbeans dependency)
+ if (tikaComments != null) {
+ tikaComments.emitAllComments(xhtml);
+ }
+
for (String header : sheetExtractor.headers) {
extractHeaderFooter(header, xhtml);
}
@@ -124,17 +124,35 @@ public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
extractHeaderFooter(footer, xhtml);
}
processDrawings(sheetPart, xhtml);
-
- //for now dump sheet hyperlinks at bottom of page
- //consider a double-pass of the inputstream to reunite hyperlinks with cells/textboxes
- //step 1: extract hyperlink info from bottom of page
- //step 2: process as we do now, but with cached hyperlink relationship info
extractHyperLinks(sheetPart, xhtml);
- // All done with this sheet
xhtml.endElement("div");
}
}
+ private static final String RELATION_COMMENTS =
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
+
+ private TikaXSSFBCommentsTable parseBinaryComments(PackagePart sheetPart) {
+ try {
+ PackageRelationshipCollection rels =
+ sheetPart.getRelationshipsByType(RELATION_COMMENTS);
+ if (rels.isEmpty()) {
+ return null;
+ }
+ PackageRelationship rel = rels.getRelationship(0);
+ PackagePartName partName =
+ PackagingURIHelper.createPartName(rel.getTargetURI());
+ PackagePart commentsPart = rel.getPackage().getPart(partName);
+ if (commentsPart == null) {
+ return null;
+ }
+ try (InputStream is = commentsPart.getInputStream()) {
+ return new TikaXSSFBCommentsTable(is);
+ }
+ } catch (InvalidFormatException | IOException e) {
+ return null;
+ }
+ }
@Override
protected void extractHeaderFooter(String hf, XHTMLContentHandler xhtml) throws SAXException {
@@ -142,16 +160,4 @@ public class XSSFBExcelExtractorDecorator extends XSSFExcelExtractorDecorator {
xhtml.element("p", hf);
}
}
-
-
- private void processSheet(SheetContentsHandler sheetContentsExtractor,
- XSSFBCommentsTable comments, XSSFBStylesTable styles,
- XSSFBSharedStringsTable strings, InputStream sheetInputStream)
- throws IOException, SAXException {
-
- XSSFBSheetHandler xssfbSheetHandler =
- new XSSFBSheetHandler(sheetInputStream, styles, comments, strings,
- sheetContentsExtractor, formatter, false);
- xssfbSheetHandler.parse();
- }
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFExcelExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFExcelExtractorDecorator.java
index 899016caf8..dba6dab4eb 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFExcelExtractorDecorator.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XSSFExcelExtractorDecorator.java
@@ -26,7 +26,6 @@ import java.util.Locale;
import java.util.Map;
import org.apache.poi.hssf.extractor.ExcelExtractor;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -42,7 +41,6 @@ import org.apache.poi.ss.usermodel.HeaderFooter;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
-import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.helpers.HeaderFooterHelper;
import org.xml.sax.Attributes;
@@ -102,13 +100,11 @@ public class XSSFExcelExtractorDecorator extends AbstractOOXMLExtractor {
protected Metadata metadata;
protected ParseContext parseContext;
- public XSSFExcelExtractorDecorator(ParseContext context, POIXMLTextExtractor extractor,
+ public XSSFExcelExtractorDecorator(ParseContext context, OPCPackage pkg,
Locale locale) {
- super(context, extractor);
+ super(context, pkg);
this.parseContext = context;
- this.extractor = (XSSFEventBasedExcelExtractor) extractor;
- configureExtractor(this.extractor, locale);
if (locale == null) {
formatter = new TikaExcelDataFormatter();
@@ -122,19 +118,9 @@ public class XSSFExcelExtractorDecorator extends AbstractOOXMLExtractor {
}
}
- protected void configureExtractor(POIXMLTextExtractor extractor, Locale locale) {
- ((XSSFEventBasedExcelExtractor) extractor)
- .setIncludeTextBoxes(config.isIncludeShapeBasedContent());
- ((XSSFEventBasedExcelExtractor) extractor).setFormulasNotResults(false);
- ((XSSFEventBasedExcelExtractor) extractor).setLocale(locale);
- //given that we load our own shared strings table, setting:
- //((XSSFEventBasedExcelExtractor)extractor).setConcatenatePhoneticRuns();
- //does no good here.
- }
-
@Override
public MetadataExtractor getMetadataExtractor() {
- return new SAXBasedMetadataExtractor(extractor.getPackage(), parseContext);
+ return new SAXBasedMetadataExtractor(opcPackage, parseContext);
}
@Override
@@ -154,7 +140,7 @@ public class XSSFExcelExtractorDecorator extends AbstractOOXMLExtractor {
@Override
protected void buildXHTML(XHTMLContentHandler xhtml)
throws SAXException, IOException {
- OPCPackage container = extractor.getPackage();
+ OPCPackage container = opcPackage;
XSSFSharedStringsShim stringsShim;
XSSFReader.SheetIterator iter;
@@ -916,7 +902,7 @@ public class XSSFExcelExtractorDecorator extends AbstractOOXMLExtractor {
//add main document so that macros can be extracted
//by AbstractOOXMLExtractor
- parts.addAll(extractor.getPackage()
+ parts.addAll(opcPackage
.getPartsByRelationshipType(PackageRelationshipTypes.CORE_DOCUMENT));
return parts;
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFWordExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFWordExtractorDecorator.java
deleted file mode 100644
index dfb4c71924..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/XWPFWordExtractorDecorator.java
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import java.io.IOException;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.xml.namespace.QName;
-
-import com.microsoft.schemas.vml.impl.CTShapeImpl;
-import org.apache.poi.ooxml.POIXMLDocumentPart;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.openxml4j.opc.PackageRelationship;
-import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
-import org.apache.poi.xssf.usermodel.XSSFRelation;
-import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
-import org.apache.poi.xwpf.model.XWPFCommentsDecorator;
-import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
-import org.apache.poi.xwpf.usermodel.BodyType;
-import org.apache.poi.xwpf.usermodel.IBody;
-import org.apache.poi.xwpf.usermodel.IBodyElement;
-import org.apache.poi.xwpf.usermodel.ICell;
-import org.apache.poi.xwpf.usermodel.IRunElement;
-import org.apache.poi.xwpf.usermodel.ISDTContent;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFEndnote;
-import org.apache.poi.xwpf.usermodel.XWPFFootnote;
-import org.apache.poi.xwpf.usermodel.XWPFHeaderFooter;
-import org.apache.poi.xwpf.usermodel.XWPFHyperlink;
-import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFPicture;
-import org.apache.poi.xwpf.usermodel.XWPFPictureData;
-import org.apache.poi.xwpf.usermodel.XWPFRelation;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.apache.poi.xwpf.usermodel.XWPFSDT;
-import org.apache.poi.xwpf.usermodel.XWPFSDTCell;
-import org.apache.poi.xwpf.usermodel.XWPFStyle;
-import org.apache.poi.xwpf.usermodel.XWPFStyles;
-import org.apache.poi.xwpf.usermodel.XWPFTable;
-import org.apache.poi.xwpf.usermodel.XWPFTableCell;
-import org.apache.poi.xwpf.usermodel.XWPFTableRow;
-import org.apache.xmlbeans.XmlCursor;
-import org.apache.xmlbeans.XmlObject;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFldChar;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTObject;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.tika.io.TikaInputStream;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.EMFParser;
-import org.apache.tika.parser.microsoft.FormattingUtils;
-import org.apache.tika.parser.microsoft.WordExtractor;
-import org.apache.tika.parser.microsoft.WordExtractor.TagAndStyle;
-import org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFFeatureExtractor;
-import org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFNumberingShim;
-import org.apache.tika.sax.ToTextContentHandler;
-import org.apache.tika.sax.XHTMLContentHandler;
-import org.apache.tika.utils.StringUtils;
-
-public class XWPFWordExtractorDecorator extends AbstractOOXMLExtractor {
-
- // could be improved by using the real delimiter in xchFollow [MS-DOC], v20140721, 2.4.6.3,
- // Part 3, Step 3
- private static final String LIST_DELIMITER = " ";
-
- //include all parts that might have embedded objects
- private final static String[] MAIN_PART_RELATIONS =
- new String[]{XWPFRelation.HEADER.getRelation(), XWPFRelation.FOOTER.getRelation(),
- XWPFRelation.FOOTNOTE.getRelation(),
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes",
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
- AbstractOOXMLExtractor.RELATION_DIAGRAM_DATA};
-
-
- private XWPFDocument document;
- private XWPFStyles styles;
- private Metadata metadata;
-
- //This is a map of the rIds of embedded files and the EmbeddedPartMetadata
- //that may be associated with the embedded file. The EmbeddedPartMetadata
- //is populated during the parse of the main document.
- private Map<String, EmbeddedPartMetadata> embeddedPartMetadataMap = new HashMap<>();
-
- public XWPFWordExtractorDecorator(Metadata metadata, ParseContext context,
- XWPFWordExtractor extractor) {
- super(context, extractor);
- this.metadata = metadata;
- document = (XWPFDocument) extractor.getDocument();
- styles = document.getStyles();
- }
-
- /**
- * @see org.apache.poi.xwpf.extractor.XWPFWordExtractor#getText()
- */
- @Override
- protected void buildXHTML(XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- XWPFHeaderFooterPolicy hfPolicy = document.getHeaderFooterPolicy();
- XWPFListManager listManager = new XWPFListManager(loadNumbering());
- // headers
- if (hfPolicy != null && config.isIncludeHeadersAndFooters()) {
- extractHeaders(xhtml, hfPolicy, listManager);
- }
-
- // process text in the order that it occurs in
- extractIBodyText(document, listManager, xhtml);
- extractFeatures(document, metadata);
-
- //handle the diagram data
- handleGeneralTextContainingPart(RELATION_DIAGRAM_DATA, "diagram-data",
- document.getPackagePart(), metadata,
- new OOXMLWordAndPowerPointTextHandler(new OOXMLTikaBodyPartHandler(xhtml),
- new HashMap<>()//empty
- ));
- //handle chart data
- handleGeneralTextContainingPart(XSSFRelation.CHART.getRelation(), "chart",
- document.getPackagePart(), metadata,
- new OOXMLWordAndPowerPointTextHandler(new OOXMLTikaBodyPartHandler(xhtml),
- new HashMap<>()//empty
- ));
-
- // then all document footers
- if (hfPolicy != null && config.isIncludeHeadersAndFooters()) {
- extractFooters(xhtml, hfPolicy, listManager);
- }
- }
-
- private XWPFNumberingShim loadNumbering() {
- try {
- PackageRelationshipCollection numberingParts =
- document.getPackagePart().getRelationshipsByType(
- XWPFRelation.NUMBERING.getRelation());
- if (numberingParts.size() > 0) {
- PackageRelationship rel = numberingParts.getRelationship(0);
- if (rel != null) {
- PackagePart numberingPart = document.getPackagePart().getRelatedPart(rel);
- if (numberingPart != null) {
- return new XWPFNumberingShim(numberingPart, getParseContext());
- }
- }
- }
- } catch (Exception e) {
- //swallow
- }
- return XWPFNumberingShim.EMPTY;
- }
-
- private void extractFeatures(XWPFDocument document, Metadata metadata) {
- XWPFFeatureExtractor ex = new XWPFFeatureExtractor();
- ex.process(document, metadata, getParseContext());
- }
-
- @Override
- protected Map<String, EmbeddedPartMetadata> getEmbeddedPartMetadataMap() {
- return embeddedPartMetadataMap;
- }
-
- private void extractIBodyText(IBody bodyElement, XWPFListManager listManager,
- XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- for (IBodyElement element : bodyElement.getBodyElements()) {
- if (element instanceof XWPFParagraph) {
- XWPFParagraph paragraph = (XWPFParagraph) element;
- extractParagraph(paragraph, listManager, xhtml);
- }
- if (element instanceof XWPFTable) {
- XWPFTable table = (XWPFTable) element;
- extractTable(table, listManager, xhtml);
- }
- if (element instanceof XWPFSDT) {
- extractSDT((XWPFSDT) element, xhtml);
- }
-
- }
- }
-
- private void extractSDT(XWPFSDT element, XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- ISDTContent content = element.getContent();
- String tag = "p";
- xhtml.startElement(tag);
- xhtml.characters(content.getText());
- xhtml.endElement(tag);
- }
-
- private void extractParagraph(XWPFParagraph paragraph, XWPFListManager listManager,
- XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- // If this paragraph is actually a whole new section, then
- // it could have its own headers and footers
- // Check and handle if so
- XWPFHeaderFooterPolicy headerFooterPolicy = null;
- if (paragraph.getCTP().getPPr() != null) {
- CTSectPr ctSectPr = paragraph.getCTP().getPPr().getSectPr();
- if (ctSectPr != null && config.isIncludeHeadersAndFooters()) {
- headerFooterPolicy = new XWPFHeaderFooterPolicy(document, ctSectPr);
- extractHeaders(xhtml, headerFooterPolicy, listManager);
- }
- }
-
- // Is this a paragraph, or a heading?
- String tag = "p";
- String styleClass = null;
- //TIKA-2144 check that styles is not null
- if (paragraph.getStyleID() != null && styles != null) {
- XWPFStyle style = styles.getStyle(paragraph.getStyleID());
-
- if (style != null && style.getName() != null) {
- TagAndStyle tas = WordExtractor.buildParagraphTagAndStyle(style.getName(),
- paragraph.getPartType() == BodyType.TABLECELL);
- tag = tas.getTag();
- styleClass = tas.getStyleClass();
- }
- }
-
- if (styleClass == null) {
- xhtml.startElement(tag);
- } else {
- xhtml.startElement(tag, "class", styleClass);
- }
-
- writeParagraphNumber(paragraph, listManager, xhtml);
-
- // Output placeholder for any embedded docs:
- processEmbeddedObjects(paragraph.getRuns(), xhtml);
-
- // Attach bookmarks for the paragraph
- // (In future, we might put them in the right place, for now
- // we just put them in the correct paragraph)
- for (int i = 0; i < paragraph.getCTP().sizeOfBookmarkStartArray(); i++) {
- CTBookmark bookmark = paragraph.getCTP().getBookmarkStartArray(i);
- xhtml.startElement("a", "name", bookmark.getName());
- xhtml.endElement("a");
- }
-
- Deque<FormattingUtils.Tag> formattingState = new ArrayDeque<>();
-
- //hyperlinks may or may not have hyperlink ids
- String lastHyperlinkId = null;
- boolean inHyperlink = false;
- // Track field-based hyperlinks (using instrText/fldChar)
- FieldHyperlinkTracker fieldTracker = new FieldHyperlinkTracker();
- boolean inFieldHyperlink = false;
-
- // Do the iruns
- for (IRunElement run : paragraph.getIRuns()) {
- // Check for field-based hyperlinks first (instrText HYPERLINK)
- if (run instanceof XWPFRun) {
- XWPFRun xwpfRun = (XWPFRun) run;
- boolean wasInFieldHyperlink = fieldTracker.isInFieldHyperlink();
- String fieldUrl = extractFieldLinks(xwpfRun, fieldTracker);
-
- // If we just entered a field hyperlink, open the anchor tag
- if (fieldUrl != null && !inFieldHyperlink) {
- // Close any existing relationship-based hyperlink first
- if (inHyperlink) {
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- xhtml.endElement("a");
- inHyperlink = false;
- lastHyperlinkId = null;
- }
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- xhtml.startElement("a", "href", fieldUrl);
- inFieldHyperlink = true;
- metadata.set(Office.HAS_FIELD_HYPERLINKS, true);
- }
-
- // If we just exited a field hyperlink, close the anchor tag
- if (wasInFieldHyperlink && !fieldTracker.isInFieldHyperlink() && inFieldHyperlink) {
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- xhtml.endElement("a");
- inFieldHyperlink = false;
- }
-
- // Emit any external refs (INCLUDEPICTURE, INCLUDETEXT, IMPORT, LINK) as anchors
- if (fieldTracker.getLastExternalRefUrl() != null) {
- AttributesImpl extRefAtts = new AttributesImpl();
- extRefAtts.addAttribute("", "class", "class", "CDATA",
- "external-ref-" + fieldTracker.getLastExternalRefType());
- extRefAtts.addAttribute("", "href", "href", "CDATA",
- fieldTracker.getLastExternalRefUrl());
- xhtml.startElement("a", extRefAtts);
- xhtml.endElement("a");
- metadata.set(Office.HAS_FIELD_HYPERLINKS, true);
- fieldTracker.clearExternalRef();
- }
- }
-
- if (run instanceof XWPFHyperlinkRun) {
- XWPFHyperlinkRun hyperlinkRun = (XWPFHyperlinkRun) run;
- if (hyperlinkRun.getHyperlinkId() == null ||
- !hyperlinkRun.getHyperlinkId().equals(lastHyperlinkId)) {
- if (inHyperlink) {
- //close out the old one
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- xhtml.endElement("a");
- inHyperlink = false;
- }
- lastHyperlinkId = hyperlinkRun.getHyperlinkId();
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- XWPFHyperlink link = hyperlinkRun.getHyperlink(document);
- if (link != null && link.getURL() != null) {
- xhtml.startElement("a", "href", link.getURL());
- inHyperlink = true;
- } else if (hyperlinkRun.getAnchor() != null &&
- hyperlinkRun.getAnchor().length() > 0) {
- xhtml.startElement("a", "href", "#" + hyperlinkRun.getAnchor());
- inHyperlink = true;
- }
- }
- } else if (inHyperlink) {
- //if this isn't a hyperlink, but the last one was
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- xhtml.endElement("a");
- lastHyperlinkId = null;
- inHyperlink = false;
- }
-
- if (run instanceof XWPFSDT) {
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- processSDTRun((XWPFSDT) run, xhtml);
- //for now, we're ignoring formatting in sdt
- //if you hit an sdt reset to false
- } else {
- processRun((XWPFRun) run, paragraph, xhtml, formattingState);
- }
- }
- FormattingUtils.closeStyleTags(xhtml, formattingState);
- if (inHyperlink) {
- xhtml.endElement("a");
- }
- if (inFieldHyperlink) {
- xhtml.endElement("a");
- }
-
-
- // Now do any comments for the paragraph
- XWPFCommentsDecorator comments = new XWPFCommentsDecorator(paragraph, null);
- String commentText = comments.getCommentText();
- if (commentText != null && commentText.length() > 0) {
- xhtml.characters(commentText);
- }
-
- // Also extract any paragraphs embedded in text boxes
- //Note "w:txbxContent//"...must look for all descendant paragraphs
- //not just the immediate children of txbxContent -- TIKA-2807
- if (config.isIncludeShapeBasedContent()) {
- try {
- for (XmlObject embeddedParagraph : paragraph.getCTP().selectPath(
- "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' declare namespace wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape' .//*/wps:txbx/w:txbxContent//w:p")) {
- extractParagraph(new XWPFParagraph(CTP.Factory.parse(embeddedParagraph.xmlText()),
- paragraph.getBody()), listManager, xhtml);
- }
- } catch (Exception e) {
- // XmlException from CTP.Factory.parse — swallow for shape content
- }
- }
-
- // Finish this paragraph
- xhtml.endElement(tag);
-
- // Extract footnote/endnote content after the paragraph close tag
- // to avoid invalid nested block elements (TIKA-4657)
- extractFootnoteEndnoteContent(paragraph, listManager, xhtml);
-
- if (headerFooterPolicy != null && config.isIncludeHeadersAndFooters()) {
- extractFooters(xhtml, headerFooterPolicy, listManager);
- }
- }
-
- private void extractFootnoteEndnoteContent(XWPFParagraph paragraph,
- XWPFListManager listManager,
- XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- String nsW = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
- QName footnoteRefQName = new QName(nsW, "footnoteReference");
- QName endnoteRefQName = new QName(nsW, "endnoteReference");
- QName idQName = new QName(nsW, "id");
- for (XmlObject obj : paragraph.getCTP().selectPath(
- "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'"
- + " .//w:footnoteReference | .//w:endnoteReference")) {
- XmlObject idAttr = obj.selectAttribute(idQName);
- if (idAttr == null) {
- continue;
- }
- int id;
- try {
- id = Integer.parseInt(idAttr.getDomNode().getNodeValue());
- } catch (NumberFormatException e) {
- continue;
- }
- boolean isFootnote = obj.getDomNode().getLocalName().equals("footnoteReference");
- if (isFootnote) {
- XWPFFootnote footnote = document.getFootnoteByID(id);
- if (footnote != null) {
- xhtml.startElement("div", "class", "footnote");
- extractIBodyText(footnote, listManager, xhtml);
- xhtml.endElement("div");
- }
- } else {
- XWPFEndnote endnote = document.getEndnoteByID(id);
- if (endnote != null) {
- xhtml.startElement("div", "class", "endnote");
- extractIBodyText(endnote, listManager, xhtml);
- xhtml.endElement("div");
- }
- }
- }
- }
-
- private void processEmbeddedObjects(List<XWPFRun> runs, XHTMLContentHandler xhtml)
- throws SAXException {
- // TODO: replace w/ XPath/XQuery:
- for (XWPFRun run : runs) {
- try (XmlCursor c = run.getCTR().newCursor()) {
- c.selectPath("./*");
- while (c.toNextSelection()) {
- XmlObject o = c.getObject();
- if (o instanceof CTObject) {
- try (XmlCursor objectCursor = o.newCursor()) {
- processObject(objectCursor, xhtml);
- }
- }
- }
- }
- }
- }
-
- private void processObject(XmlCursor cursor, XHTMLContentHandler xhtml) throws SAXException {
-
- cursor.selectPath("./*");
- String objectRelId = null;
- String progId = null;
- EmbeddedPartMetadata embeddedPartMetadata = null;
- while (cursor.toNextSelection()) {
- XmlObject o2 = cursor.getObject();
- XmlObject embedAtt = o2.selectAttribute(new QName("Type"));
- if (embedAtt != null &&
- embedAtt.getDomNode().getNodeValue().equals("Embed")) {
- //TODO: get ProgID, while we're here?
- // Type is "Embed"
- XmlObject relIDAtt = o2.selectAttribute(new QName(
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
- "id"));
- if (relIDAtt != null) {
- objectRelId = relIDAtt.getDomNode().getNodeValue();
- }
-
- XmlObject progIDAtt = o2.selectAttribute(new QName("ProgID"));
- if (progIDAtt != null) {
- progId = progIDAtt.getDomNode().getNodeValue();
- }
- } else if (o2 instanceof CTShapeImpl) {
- XmlObject[] imagedata = o2.selectChildren(
- new QName("urn:schemas" +
- "-microsoft-com:vml","imagedata"));
- if (imagedata.length > 0) {
- XmlObject relIDAtt = imagedata[0].selectAttribute(new QName(
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
- "id"));
- if (relIDAtt != null) {
- String rid = relIDAtt.getDomNode().getNodeValue();
- embeddedPartMetadata = new EmbeddedPartMetadata(rid);
- tryToParseEmbeddedName(rid, embeddedPartMetadata);
- }
- }
- }
- }
- if (objectRelId == null) {
- return;
- }
-
- if (embeddedPartMetadata != null) {
- if (! StringUtils.isBlank(progId)) {
- embeddedPartMetadata.setProgId(progId);
- }
- embeddedPartMetadataMap.put(objectRelId, embeddedPartMetadata);
- }
- AttributesImpl attributes = new AttributesImpl();
- attributes.addAttribute("", "class", "class", "CDATA", "embedded");
- attributes.addAttribute("", "id", "id", "CDATA", objectRelId);
- if (embeddedPartMetadata != null && !StringUtils.isBlank(embeddedPartMetadata.getFullName())) {
- attributes.addAttribute("", "name", "name", "CDATA",
- embeddedPartMetadata.getFullName());
- }
- xhtml.startElement("div", attributes);
- xhtml.endElement("div");
- }
-
- private String tryToParseEmbeddedName(String rid, EmbeddedPartMetadata embeddedPartMetadata) {
- //This tries to parse the embedded name out of a comment
- //field in an emf
- POIXMLDocumentPart part = document.getRelationById(rid);
- if (part == null || part.getPackagePart() == null
- || part.getPackagePart().getContentType() == null) {
- return null;
- }
- PackagePart packagePart = part.getPackagePart();
- if ("image/x-emf".equals(packagePart.getContentType())) {
- try (TikaInputStream tis = TikaInputStream.get(packagePart.getInputStream())) {
- EMFParser p = new EMFParser();
- Metadata m = Metadata.newInstance(getParseContext());
- ToTextContentHandler toTextContentHandler = new ToTextContentHandler();
- p.parse(tis, toTextContentHandler, m, getParseContext());
- embeddedPartMetadata.setRenderedName(toTextContentHandler.toString().trim());
- embeddedPartMetadata.setFullName(m.get(EMFParser.EMF_ICON_STRING));
- } catch (SecurityException e) {
- throw e;
- } catch (Exception e) {
- //we tried
- }
- }
- return null;
- }
-
- private void writeParagraphNumber(XWPFParagraph paragraph, XWPFListManager listManager,
- XHTMLContentHandler xhtml) throws SAXException {
- if (paragraph.getNumIlvl() == null) {
- return;
- }
- String number = listManager.getFormattedNumber(paragraph);
- if (number != null) {
- xhtml.characters(number);
- }
-
- }
-
- private void processRun(XWPFRun run, XWPFParagraph paragraph, XHTMLContentHandler xhtml,
- Deque<FormattingUtils.Tag> formattingState)
- throws SAXException, IOException {
- // open/close required tags if run changes formatting
- FormattingUtils.ensureFormattingState(xhtml, FormattingUtils.toTags(run), formattingState);
-
- if (config.isConcatenatePhoneticRuns()) {
- xhtml.characters(run.toString());
- } else {
- xhtml.characters(run.text());
- }
-
- // If we have any pictures, output them
- for (XWPFPicture picture : run.getEmbeddedPictures()) {
- if (paragraph.getDocument() != null) {
- XWPFPictureData data = picture.getPictureData();
- if (data != null) {
- AttributesImpl attr = new AttributesImpl();
-
- attr.addAttribute("", "src", "src", "CDATA", "embedded:" + data.getFileName());
- attr.addAttribute("", "alt", "alt", "CDATA", picture.getDescription());
-
- xhtml.startElement("img", attr);
- xhtml.endElement("img");
- }
- }
- }
- }
-
- private void processSDTRun(XWPFSDT run, XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- xhtml.characters(run.getContent().getText());
- }
-
- /**
- * Extracts field-based hyperlinks from a run by examining fldChar and instrText elements.
- * This handles HYPERLINK field codes that are not relationship-based.
- *
- * @param run the run to examine
- * @param tracker the field hyperlink tracker maintaining state across runs
- * @return the hyperlink URL if this run starts a hyperlink, null otherwise
- */
- private String extractFieldLinks(XWPFRun run, FieldHyperlinkTracker tracker) {
- CTR ctr = run.getCTR();
- try (XmlCursor cursor = ctr.newCursor()) {
- if (cursor.toFirstChild()) {
- do {
- String localName = cursor.getName().getLocalPart();
- if ("fldChar".equals(localName)) {
- XmlObject obj = cursor.getObject();
- if (obj instanceof CTFldChar) {
- CTFldChar fldChar = (CTFldChar) obj;
- STFldCharType.Enum fldType = fldChar.getFldCharType();
- if (fldType == STFldCharType.BEGIN) {
- tracker.startField();
- } else if (fldType == STFldCharType.SEPARATE) {
- return tracker.separate();
- } else if (fldType == STFldCharType.END) {
- tracker.endField();
- }
- }
- } else if ("instrText".equals(localName)) {
- XmlObject obj = cursor.getObject();
- if (obj instanceof CTText) {
- CTText text = (CTText) obj;
- tracker.addInstrText(text.getStringValue());
- }
- }
- } while (cursor.toNextSibling());
- }
- }
- return null;
- }
-
- private void extractTable(XWPFTable table, XWPFListManager listManager,
- XHTMLContentHandler xhtml)
- throws SAXException, IOException {
- xhtml.startElement("table");
- xhtml.startElement("tbody");
- for (XWPFTableRow row : table.getRows()) {
- xhtml.startElement("tr");
- for (ICell cell : row.getTableICells()) {
- xhtml.startElement("td");
- if (cell instanceof XWPFTableCell) {
- extractIBodyText((XWPFTableCell) cell, listManager, xhtml);
- } else if (cell instanceof XWPFSDTCell) {
- xhtml.characters(((XWPFSDTCell) cell).getContent().getText());
- }
- xhtml.endElement("td");
- }
- xhtml.endElement("tr");
- }
- xhtml.endElement("tbody");
- xhtml.endElement("table");
- }
-
- private void extractFooters(XHTMLContentHandler xhtml, XWPFHeaderFooterPolicy hfPolicy,
- XWPFListManager listManager)
- throws SAXException, IOException {
- // footers
- if (hfPolicy.getFirstPageFooter() != null) {
- extractHeaderText(xhtml, hfPolicy.getFirstPageFooter(), listManager);
- }
- if (hfPolicy.getEvenPageFooter() != null) {
- extractHeaderText(xhtml, hfPolicy.getEvenPageFooter(), listManager);
- }
- if (hfPolicy.getDefaultFooter() != null) {
- extractHeaderText(xhtml, hfPolicy.getDefaultFooter(), listManager);
- }
- }
-
- private void extractHeaders(XHTMLContentHandler xhtml, XWPFHeaderFooterPolicy hfPolicy,
- XWPFListManager listManager)
- throws SAXException, IOException {
- if (hfPolicy == null) {
- return;
- }
-
- if (hfPolicy.getFirstPageHeader() != null) {
- extractHeaderText(xhtml, hfPolicy.getFirstPageHeader(), listManager);
- }
-
- if (hfPolicy.getEvenPageHeader() != null) {
- extractHeaderText(xhtml, hfPolicy.getEvenPageHeader(), listManager);
- }
-
- if (hfPolicy.getDefaultHeader() != null) {
- extractHeaderText(xhtml, hfPolicy.getDefaultHeader(), listManager);
- }
- }
-
- private void extractHeaderText(XHTMLContentHandler xhtml, XWPFHeaderFooter header,
- XWPFListManager listManager)
- throws SAXException, IOException {
-
- for (IBodyElement e : header.getBodyElements()) {
- if (e instanceof XWPFParagraph) {
- extractParagraph((XWPFParagraph) e, listManager, xhtml);
- } else if (e instanceof XWPFTable) {
- extractTable((XWPFTable) e, listManager, xhtml);
- } else if (e instanceof XWPFSDT) {
- extractSDT((XWPFSDT) e, xhtml);
- }
- }
- }
-
- /**
- * Include main body and anything else that can
- * have an attachment/embedded object
- */
- @Override
- protected List<PackagePart> getMainDocumentParts() {
- List<PackagePart> parts = new ArrayList<>();
- parts.add(document.getPackagePart());
- addRelatedParts(document.getPackagePart(), parts);
- return parts;
- }
-
- private void addRelatedParts(PackagePart documentPart, List<PackagePart> relatedParts) {
- for (String relation : MAIN_PART_RELATIONS) {
- PackageRelationshipCollection prc = null;
- try {
- prc = documentPart.getRelationshipsByType(relation);
- if (prc != null) {
- for (int i = 0; i < prc.size(); i++) {
- PackagePart packagePart =
- documentPart.getRelatedPart(prc.getRelationship(i));
- relatedParts.add(packagePart);
- }
- }
- } catch (InvalidFormatException e) {
- //swallow
- }
- }
-
- }
-
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSExtractorDecorator.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSExtractorDecorator.java
index ca7eec664d..e7d0a15cf1 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSExtractorDecorator.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSExtractorDecorator.java
@@ -26,8 +26,7 @@ import java.util.Map;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.io.IOUtils;
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
+import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
@@ -57,12 +56,12 @@ public class XPSExtractorDecorator extends AbstractOOXMLExtractor {
private final ZipPackage pkg;
Map<String, Metadata> embeddedImages = new LinkedHashMap<>();
- public XPSExtractorDecorator(ParseContext context, POIXMLTextExtractor extractor)
+ public XPSExtractorDecorator(ParseContext context, OPCPackage opcPackage)
throws TikaException {
- super(context, extractor);
+ super(context, opcPackage);
this.context = context;
- if (extractor.getPackage() instanceof ZipPackage) {
- this.pkg = (ZipPackage) extractor.getPackage();
+ if (opcPackage instanceof ZipPackage) {
+ this.pkg = (ZipPackage) opcPackage;
} else {
throw new TikaException("OPCPackage must be a ZipPackage");
}
@@ -88,11 +87,6 @@ public class XPSExtractorDecorator extends AbstractOOXMLExtractor {
return TikaInputStream.get(zipEntrySource.getInputStream(zipEntry));
}
- @Override
- public POIXMLDocument getDocument() {
- return null;
- }
-
@Override
protected void buildXHTML(XHTMLContentHandler xhtml) throws SAXException, IOException {
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSTextExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSTextExtractor.java
deleted file mode 100644
index a05698d969..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xps/XPSTextExtractor.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml.xps;
-
-
-import java.io.Closeable;
-import java.io.IOException;
-
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.POIXMLProperties;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-
-/**
- * Currently, mostly a pass-through class to hold pkg and properties
- * and keep the general framework similar to our other POI-integrated
- * extractors.
- */
-public class XPSTextExtractor implements POIXMLTextExtractor {
-
- private final OPCPackage pkg;
- private final POIXMLProperties properties;
-
- public XPSTextExtractor(OPCPackage pkg) throws OpenXML4JException, IOException {
- this.pkg = pkg;
- try {
- this.properties = new POIXMLProperties(pkg);
- } catch (Exception e) {
- throw new IOException("Failed to read OOXML properties", e);
- }
- }
-
- @Override
- public OPCPackage getPackage() {
- return pkg;
- }
-
- @Override
- public String getText() {
- return null;
- }
-
- @Override
- public void setCloseFilesystem(boolean b) {
-
- }
-
- @Override
- public boolean isCloseFilesystem() {
- return false;
- }
-
- @Override
- public Closeable getFilesystem() {
- return null;
- }
-
- public POIXMLProperties.CoreProperties getCoreProperties() {
- return this.properties.getCoreProperties();
- }
-
- public POIXMLProperties.ExtendedProperties getExtendedProperties() {
- return this.properties.getExtendedProperties();
- }
-
- public POIXMLProperties.CustomProperties getCustomProperties() {
- return this.properties.getCustomProperties();
- }
-
- @Override
- public POIXMLDocument getDocument() {
- return null;
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xslf/XSLFEventBasedPowerPointExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xslf/XSLFEventBasedPowerPointExtractor.java
index 3de987e67d..52d554a940 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xslf/XSLFEventBasedPowerPointExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xslf/XSLFEventBasedPowerPointExtractor.java
@@ -16,219 +16,21 @@
*/
package org.apache.tika.parser.microsoft.ooxml.xslf;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Date;
-
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.POIXMLProperties;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.tika.parser.microsoft.ooxml.EditType;
-import org.apache.tika.parser.microsoft.ooxml.ParagraphProperties;
-import org.apache.tika.parser.microsoft.ooxml.RunProperties;
-import org.apache.tika.parser.microsoft.ooxml.XWPFBodyContentsHandler;
-
-public class XSLFEventBasedPowerPointExtractor implements POIXMLTextExtractor {
-
+/**
+ * Lightweight holder for an {@link OPCPackage} for PPTX files.
+ * Content extraction is handled by {@code SXSLFPowerPointExtractorDecorator}.
+ */
+public class XSLFEventBasedPowerPointExtractor {
- private OPCPackage container;
- private POIXMLProperties properties;
+ private final OPCPackage container;
- public XSLFEventBasedPowerPointExtractor(OPCPackage container)
- throws OpenXML4JException, IOException {
+ public XSLFEventBasedPowerPointExtractor(OPCPackage container) {
this.container = container;
- try {
- this.properties = new POIXMLProperties(container);
- } catch (Exception e) {
- throw new IOException("Failed to read OOXML properties", e);
- }
}
public OPCPackage getPackage() {
return this.container;
}
-
- public POIXMLProperties.CoreProperties getCoreProperties() {
- return this.properties.getCoreProperties();
- }
-
- public POIXMLProperties.ExtendedProperties getExtendedProperties() {
- return this.properties.getExtendedProperties();
- }
-
- public POIXMLProperties.CustomProperties getCustomProperties() {
- return this.properties.getCustomProperties();
- }
-
- @Override
- public POIXMLDocument getDocument() {
- return null;
- }
-
-
- @Override
- public String getText() {
- //TODO
- return "";
- }
-
- @Override
- public void setCloseFilesystem(boolean b) {
-
- }
-
- @Override
- public boolean isCloseFilesystem() {
- return false;
- }
-
- @Override
- public Closeable getFilesystem() {
- return null;
- }
-
- @Override
- public void close() throws IOException {
- getPackage().revert();
- }
-
- private static class XSLFToTextContentHandler
- implements XWPFBodyContentsHandler {
- private final StringBuilder buffer;
-
- public XSLFToTextContentHandler(StringBuilder buffer) {
- this.buffer = buffer;
- }
-
- @Override
- public void run(RunProperties runProperties, String contents) {
- buffer.append(contents);
- }
-
- @Override
- public void hyperlinkStart(String link) {
- //no-op
- }
-
- @Override
- public void hyperlinkEnd() {
- //no-op
- }
-
- @Override
- public void startParagraph(ParagraphProperties paragraphProperties) {
- //no-op
- }
-
- @Override
- public void endParagraph() {
- buffer.append("\n");
- }
-
- @Override
- public void startTable() {
-
- }
-
- @Override
- public void endTable() {
-
- }
-
- @Override
- public void startTableRow() {
-
- }
-
- @Override
- public void endTableRow() {
- buffer.append("\n");
- }
-
- @Override
- public void startTableCell() {
-
- }
-
- @Override
- public void endTableCell() {
- buffer.append("\t");
- }
-
- @Override
- public void startSDT() {
-
- }
-
- @Override
- public void endSDT() {
-
- }
-
- @Override
- public void startEditedSection(String editor, Date date,
- EditType editType) {
-
- }
-
- @Override
- public void endEditedSection() {
-
- }
-
- @Override
- public boolean isIncludeDeletedText() {
- return false;
- }
-
- @Override
- public void footnoteReference(String id) {
-
- }
-
- @Override
- public void endnoteReference(String id) {
-
- }
-
- @Override
- public void commentReference(String id) {
-
- }
-
- @Override
- public boolean isIncludeMoveFromText() {
- return false;
- }
-
-
- @Override
- public void embeddedOLERef(String refId, String progId, String emfImageRId) {
- //no-op
- }
-
- @Override
- public void linkedOLERef(String refId) {
- //no-op
- }
-
- @Override
- public void embeddedPicRef(String picFileName, String picDescription) {
- //no-op
- }
-
- @Override
- public void startBookmark(String id, String name) {
-
- }
-
- @Override
- public void endBookmark(String id) {
-
- }
-
- }
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xwpf/XWPFEventBasedWordExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xwpf/XWPFEventBasedWordExtractor.java
index 74976ea34e..16c166a6ee 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xwpf/XWPFEventBasedWordExtractor.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/ooxml/xwpf/XWPFEventBasedWordExtractor.java
@@ -16,70 +16,23 @@
*/
package org.apache.tika.parser.microsoft.ooxml.xwpf;
-import java.io.Closeable;
import java.io.IOException;
-import java.io.InputStream;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.POIXMLProperties;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackagePart;
-import org.apache.poi.openxml4j.opc.PackageRelationship;
-import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
-import org.apache.poi.xwpf.usermodel.XWPFRelation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
-
-import org.apache.tika.exception.RuntimeSAXException;
-import org.apache.tika.exception.TikaException;
-import org.apache.tika.exception.WriteLimitReachedException;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.ooxml.AbstractOOXMLExtractor;
-import org.apache.tika.parser.microsoft.ooxml.EditType;
-import org.apache.tika.parser.microsoft.ooxml.OOXMLWordAndPowerPointTextHandler;
-import org.apache.tika.parser.microsoft.ooxml.ParagraphProperties;
-import org.apache.tika.parser.microsoft.ooxml.RunProperties;
-import org.apache.tika.parser.microsoft.ooxml.XWPFBodyContentsHandler;
-import org.apache.tika.parser.microsoft.ooxml.XWPFListManager;
-import org.apache.tika.utils.XMLReaderUtils;
-
-//TODO: move this into POI?
/**
- * Experimental class that is based on POI's XSSFEventBasedExcelExtractor
+ * Lightweight holder for an {@link OPCPackage} for DOCX files.
+ * Content extraction is handled by {@code SXWPFWordExtractorDecorator}.
*/
-public class XWPFEventBasedWordExtractor implements POIXMLTextExtractor {
-
- private static final Logger LOG = LoggerFactory.getLogger(XWPFEventBasedWordExtractor.class);
+public class XWPFEventBasedWordExtractor {
- private OPCPackage container;
- private POIXMLProperties properties;
+ private final OPCPackage container;
private boolean includeGlossary = true;
public XWPFEventBasedWordExtractor(OPCPackage container)
throws OpenXML4JException, IOException {
this.container = container;
- // Properties are lazily initialized to avoid requiring ooxml-lite
- // when SAXBasedMetadataExtractor is used instead
- }
-
- private POIXMLProperties getOrCreateProperties() {
- if (properties == null) {
- try {
- properties = new POIXMLProperties(container);
- } catch (Exception e) {
- LOG.warn("Couldn't load properties", e);
- }
- }
- return properties;
}
public OPCPackage getPackage() {
@@ -90,334 +43,7 @@ public class XWPFEventBasedWordExtractor implements POIXMLTextExtractor {
this.includeGlossary = includeGlossary;
}
- public POIXMLProperties.CoreProperties getCoreProperties() {
- POIXMLProperties props = getOrCreateProperties();
- return props != null ? props.getCoreProperties() : null;
- }
-
- public POIXMLProperties.ExtendedProperties getExtendedProperties() {
- POIXMLProperties props = getOrCreateProperties();
- return props != null ? props.getExtendedProperties() : null;
- }
-
- public POIXMLProperties.CustomProperties getCustomProperties() {
- POIXMLProperties props = getOrCreateProperties();
- return props != null ? props.getCustomProperties() : null;
- }
-
- @Override
- public POIXMLDocument getDocument() {
- return null;
- }
-
-
- @Override
- public String getText() {
- StringBuilder sb = new StringBuilder();
- //handle main document
- List<PackagePart> pps =
- container.getPartsByContentType(XWPFRelation.DOCUMENT.getContentType());
- if (pps != null) {
- for (PackagePart pp : pps) {
- //likely only one, but why not...
- try {
- handleDocumentPart(pp, sb);
- } catch (IOException e) {
- LOG.warn("IOException handling document part", e);
- } catch (SAXException e) {
- if (WriteLimitReachedException.isWriteLimitReached(e)) {
- throw new RuntimeSAXException(e);
- }
- //swallow this because we don't actually call it
- LOG.warn("SAXException handling document part", e);
- } catch (TikaException e) {
- LOG.warn("ParseException handling document part", e);
- }
- }
- }
- //handle glossary document
- if (includeGlossary) {
- pps = container.getPartsByContentType(
- XWPFRelation.GLOSSARY_DOCUMENT.getContentType());
-
- if (pps != null) {
- for (PackagePart pp : pps) {
- //likely only one, but why not...
- try {
- handleDocumentPart(pp, sb);
- } catch (IOException e) {
- LOG.warn("IOException handling glossary document part", e);
- } catch (SAXException e) {
- if (WriteLimitReachedException.isWriteLimitReached(e)) {
- throw new RuntimeSAXException(e);
- }
- //swallow this because we don't actually call it
- LOG.warn("SAXException handling glossary document part", e);
- } catch (TikaException e) {
- LOG.warn("ParseException handling document part", e);
- }
- }
- }
- }
-
- return sb.toString();
- }
-
- @Override
- public void setCloseFilesystem(boolean b) {
-
- }
-
- @Override
- public boolean isCloseFilesystem() {
- return false;
- }
-
- @Override
- public Closeable getFilesystem() {
- return null;
- }
-
-
- private void handleDocumentPart(PackagePart documentPart, StringBuilder sb)
- throws IOException, SAXException, TikaException {
- //load the numbering/list manager and styles from the main document part
- XWPFNumberingShim numbering = loadNumbering(documentPart);
- XWPFListManager xwpfListManager = new XWPFListManager(
- numbering != null ? numbering : XWPFNumberingShim.EMPTY);
- //TODO: XWPFStyles styles = loadStyles(documentPart);
-
- //headers
- try {
- PackageRelationshipCollection headersPRC =
- documentPart.getRelationshipsByType(XWPFRelation.HEADER.getRelation());
- if (headersPRC != null) {
- for (int i = 0; i < headersPRC.size(); i++) {
- PackagePart header = AbstractOOXMLExtractor.safeGetRelatedPart(
- documentPart, headersPRC.getRelationship(i));
- if (header == null) {
- continue;
- }
- handlePart(header, xwpfListManager, sb);
- }
- }
- } catch (InvalidFormatException e) {
- LOG.warn("Invalid format", e);
- }
-
- //main document
- handlePart(documentPart, xwpfListManager, sb);
-
- //for now, just dump other components at end
- for (XWPFRelation rel : new XWPFRelation[]{XWPFRelation.FOOTNOTE, XWPFRelation.COMMENT,
- XWPFRelation.FOOTER, XWPFRelation.ENDNOTE}) {
- try {
- PackageRelationshipCollection prc =
- documentPart.getRelationshipsByType(rel.getRelation());
- if (prc != null) {
- for (int i = 0; i < prc.size(); i++) {
- PackagePart packagePart =
- AbstractOOXMLExtractor.safeGetRelatedPart(
- documentPart, prc.getRelationship(i));
- if (packagePart == null) {
- continue;
- }
- handlePart(packagePart, xwpfListManager, sb);
- }
- }
- } catch (InvalidFormatException e) {
- LOG.warn("Invalid format", e);
- }
- }
- }
-
- private void handlePart(PackagePart packagePart, XWPFListManager xwpfListManager,
- StringBuilder buffer) throws IOException, SAXException, TikaException {
-
- Map<String, String> hyperlinks = loadHyperlinkRelationships(packagePart);
- try (InputStream stream = packagePart.getInputStream()) {
- XMLReaderUtils.parseSAX(stream,
- new OOXMLWordAndPowerPointTextHandler(new XWPFToTextContentHandler(buffer),
- hyperlinks), new ParseContext());
- }
-
- }
-
- private Map<String, String> loadHyperlinkRelationships(PackagePart bodyPart) {
- Map<String, String> hyperlinks = new HashMap<>();
- try {
- PackageRelationshipCollection prc =
- bodyPart.getRelationshipsByType(XWPFRelation.HYPERLINK.getRelation());
- for (int i = 0; i < prc.size(); i++) {
- PackageRelationship pr = prc.getRelationship(i);
- if (pr == null) {
- continue;
- }
- String id = pr.getId();
- String url = (pr.getTargetURI() == null) ? null : pr.getTargetURI().toString();
- if (id != null && url != null) {
- hyperlinks.put(id, url);
- }
- }
- } catch (InvalidFormatException e) {
- LOG.warn("Invalid format", e);
- }
- return hyperlinks;
- }
-
- private XWPFNumberingShim loadNumbering(PackagePart packagePart) {
- try {
- PackageRelationshipCollection numberingParts =
- packagePart.getRelationshipsByType(XWPFRelation.NUMBERING.getRelation());
- if (numberingParts.size() > 0) {
- PackageRelationship numberingRelationShip = numberingParts.getRelationship(0);
- if (numberingRelationShip == null) {
- return null;
- }
- PackagePart numberingPart = container.getPart(numberingRelationShip);
- if (numberingPart == null) {
- return null;
- }
- return new XWPFNumberingShim(numberingPart, new ParseContext());
- }
- } catch (Exception e) {
- LOG.warn("Couldn't load numbering", e);
- }
- return null;
- }
-
- private static class XWPFToTextContentHandler
- implements XWPFBodyContentsHandler {
- private final StringBuilder buffer;
-
- public XWPFToTextContentHandler(StringBuilder buffer) {
- this.buffer = buffer;
- }
-
- @Override
- public void run(RunProperties runProperties, String contents) {
- buffer.append(contents);
- }
-
- @Override
- public void hyperlinkStart(String link) {
- //no-op
- }
-
- @Override
- public void hyperlinkEnd() {
- //no-op
- }
-
- @Override
- public void startParagraph(ParagraphProperties paragraphProperties) {
- //no-op
- }
-
- @Override
- public void endParagraph() {
- buffer.append("\n");
- }
-
- @Override
- public void startTable() {
-
- }
-
- @Override
- public void endTable() {
-
- }
-
- @Override
- public void startTableRow() {
-
- }
-
- @Override
- public void endTableRow() {
- buffer.append("\n");
- }
-
- @Override
- public void startTableCell() {
-
- }
-
- @Override
- public void endTableCell() {
- buffer.append("\t");
- }
-
- @Override
- public void startSDT() {
-
- }
-
- @Override
- public void endSDT() {
- buffer.append("\n");
- }
-
- @Override
- public void startEditedSection(String editor, Date date,
- EditType editType) {
-
- }
-
- @Override
- public void endEditedSection() {
-
- }
-
- @Override
- public boolean isIncludeDeletedText() {
- return true;
- }
-
- @Override
- public void footnoteReference(String id) {
-
- }
-
- @Override
- public void endnoteReference(String id) {
-
- }
-
- @Override
- public void commentReference(String id) {
-
- }
-
- @Override
- public boolean isIncludeMoveFromText() {
- return false;
- }
-
- @Override
- public void embeddedOLERef(String refId, String progId, String emfImageRId) {
- //no-op
- }
-
- @Override
- public void linkedOLERef(String refId) {
- //no-op
- }
-
- @Override
- public void embeddedPicRef(String picFileName, String picDescription) {
- //no-op
- }
-
- @Override
- public void startBookmark(String id, String name) {
- //no-op
- }
-
- @Override
- public void endBookmark(String id) {
- //no-op
- }
+ public boolean isIncludeGlossary() {
+ return includeGlossary;
}
}
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/AbstractOOXMLDocxTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLDocxTest.java
deleted file mode 100644
index 7407e169c6..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLDocxTest.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.tika.TikaTest;
-import org.apache.tika.metadata.DublinCore;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.metadata.OfficeOpenXMLExtended;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
-
-public abstract class AbstractOOXMLDocxTest extends TikaTest {
-
- abstract ParseContext getParseContext();
-
- protected OfficeParserConfig getOrCreateOfficeParserConfig(ParseContext parseContext) {
- OfficeParserConfig config = parseContext.get(OfficeParserConfig.class);
- if (config == null) {
- config = new OfficeParserConfig();
- parseContext.set(OfficeParserConfig.class, config);
- }
- return config;
- }
-
- /**
- * Test the plain text output of the Word converter
- *
- * @throws Exception
- */
- @Test
- public void testWord() throws Exception {
-
- XMLResult xmlResult = getXML("testWORD.docx", getParseContext());
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- xmlResult.metadata.get(Metadata.CONTENT_TYPE));
- assertEquals("Sample Word Document", xmlResult.metadata.get(TikaCoreProperties.TITLE));
- assertEquals("Keith Bennett", xmlResult.metadata.get(TikaCoreProperties.CREATOR));
- assertTrue(xmlResult.xml.contains("Sample Word Document"));
-
- }
-
- /**
- * Test the plain text output of the Word converter
- *
- * @throws Exception
- */
- @Test
- public void testWordFootnote() throws Exception {
- XMLResult xmlResult = getXML("footnotes.docx", getParseContext());
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- xmlResult.metadata.get(Metadata.CONTENT_TYPE));
- assertTrue(xmlResult.xml.contains("snoska"));
- //TIKA-4657 -- footnote content should be in a div with class "footnote"
- // and should not be nested inside the paragraph
- assertContains("<div class=\"footnote\">", xmlResult.xml);
- assertNotContained("<p><div class=\"footnote\">", xmlResult.xml);
- }
-
- @Test
- public void testEndnoteWithTable() throws Exception {
- XMLResult xmlResult = getXML("testWORD_endnote_table.docx", getParseContext());
- assertContains("Cat Property Act", xmlResult.xml);
- //TIKA-4657 -- endnote content should be in a div with class "endnote"
- assertContains("<div class=\"endnote\">", xmlResult.xml);
- }
-
- /**
- * 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", getParseContext());
- String xml = result.xml;
- Metadata metadata = result.metadata;
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- metadata.get(Metadata.CONTENT_TYPE));
- assertEquals("Sample Word Document", metadata.get(TikaCoreProperties.TITLE));
- assertEquals("Keith Bennett", metadata.get(TikaCoreProperties.CREATOR));
- assertTrue(xml.contains("Sample Word Document"));
- // Check that custom headings came through
- assertTrue(xml.contains("<h1 class=\"title\">"));
-
- // Regular headings
- assertContains("<h1>Heading Level 1</h1>", xml);
- assertTrue(xml.contains("<h2>Heading Level 2</h2>"));
- // Headings with anchor tags in them
- // Bookmark position relative to text differs between DOM and SAX
- assertContains("Heading Level 3", xml);
- assertContains("<a name=\"OnLevel3\" />", xml);
- // Bold and italic
- assertTrue(xml.contains("<b>BOLD</b>"));
- assertTrue(xml.contains("<i>ITALIC</i>"));
- // Table
- assertTrue(xml.contains("<table>"));
- assertTrue(xml.contains("<td>"));
- // Links
- assertTrue(xml.contains("<a href=\"http://tika.apache.org/\">Tika</a>"));
- // Anchor links
- assertContains("<a href=\"#OnMainHeading\">The Main Heading Bookmark</a>", xml);
- // Paragraphs with other styles
- assertTrue(xml.contains("<p class=\"signature\">This one"));
-
- result = getXML("testWORD_3imgs.docx", getParseContext());
- xml = result.xml;
-
- // Images 2-4 (there is no 1!)
- assertTrue(xml.contains("<img src=\"embedded:image2.png\" alt=\"A description...\" />"),
- "Image not found in:\n" + xml);
- assertTrue(xml.contains("<img src=\"embedded:image3.jpeg\" alt=\"A description...\" />"),
- "Image not found in:\n" + xml);
- assertTrue(xml.contains("<img src=\"embedded:image4.png\" alt=\"A description...\" />"),
- "Image not found in:\n" + xml);
-
- // Text too
- assertTrue(xml.contains("<p>The end!</p>"));
- }
-
- /**
- * Test that we can extract image from docx header
- */
- @Test
- public void testWordPicturesInHeader() throws Exception {
- List<Metadata> metadataList = getRecursiveMetadata("headerPic.docx", getParseContext());
- assertEquals(2, metadataList.size());
- Metadata m = metadataList.get(0);
- String mainContent = m.get(TikaCoreProperties.TIKA_CONTENT);
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- m.get(Metadata.CONTENT_TYPE));
- // Check that custom headings came through
- assertTrue(mainContent.contains("<img"));
- }
-
- /**
- * Test docx without headers
- * TIKA-633
- */
- @Test
- public void testNullHeaders() throws Exception {
- XMLResult xmlResult = getXML("NullHeader.docx", getParseContext());
- assertEquals(false, xmlResult.xml.isEmpty(), "Should have found some text");
- }
-
- /**
- * Test for missing text described in
- * <a href="https://issues.apache.org/jira/browse/TIKA-1130">TIKA-1130</a>.
- * and TIKA-1317
- */
- @Test
- public void testMissingText() throws Exception {
-
- XMLResult xmlResult = getXML("testWORD_missing_text.docx", getParseContext());
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- xmlResult.metadata.get(Metadata.CONTENT_TYPE));
- assertContains("BigCompany", xmlResult.xml);
- assertContains("Seasoned", xmlResult.xml);
- assertContains("Rich_text_in_cell", xmlResult.xml);
-
- }
-
- @Test
- public void testBoldHyperlink() throws Exception {
- //TIKA-1255
- String xml = getXML("testWORD_boldHyperlink.docx", getParseContext()).xml;
- xml = xml.replaceAll("\\s+", " ");
- assertContains("<a href=\"http://tika.apache.org/\">hyper <b>link</b></a>", xml);
- assertContains("<a href=\"http://tika.apache.org/\"><b>hyper</b> link</a>; bold", xml);
- }
-
- @Test
- public void testLongForIntExceptionInSummaryDetails() throws Exception {
- //TIKA-2055
- assertContains("bold",
- getXML("testWORD_totalTimeOutOfRange.docx", getParseContext()).xml);
- }
-
- @Test
- public void testMultiAuthorsManagers() throws Exception {
- XMLResult r = getXML("testWORD_multi_authors.docx", getParseContext());
- String[] authors = r.metadata.getValues(TikaCoreProperties.CREATOR);
- assertEquals(3, authors.length);
- assertEquals("author2", authors[1]);
-
- String[] managers = r.metadata.getValues(OfficeOpenXMLExtended.MANAGER);
- assertEquals(2, managers.length);
- assertEquals("manager1", managers[0]);
- assertEquals("manager2", managers[1]);
- }
-
- @Test
- public void testOrigSourcePath() throws Exception {
- Metadata embed1_zip_metadata =
- getRecursiveMetadata("test_recursive_embedded.docx", getParseContext()).get(2);
- assertContains("C:\\Users\\tallison\\AppData\\Local\\Temp\\embed1.zip", Arrays.asList(
- embed1_zip_metadata.getValues(TikaCoreProperties.ORIGINAL_RESOURCE_NAME)));
- assertContains("C:\\Users\\tallison\\Desktop\\tmp\\New folder (2)\\embed1.zip",
- Arrays.asList(
- embed1_zip_metadata.getValues(
- TikaCoreProperties.ORIGINAL_RESOURCE_NAME)));
- }
-
- @Test
- public void testDOCXThumbnail() throws Exception {
- String xml = getXML("testDOCX_Thumbnail.docx", getParseContext()).xml;
- int a = xml.indexOf("This file contains a thumbnail");
- int b = xml.indexOf("<div class=\"embedded\" id=\"/docProps/thumbnail.emf\" />");
- assertTrue(a != -1);
- assertTrue(b != -1);
- assertTrue(a < b);
- }
-
- @Test
- public void testWordCustomProperties() throws Exception {
- ParseContext context = new ParseContext();
- context.set(Locale.class, Locale.US);
- Metadata metadata = getXML("testWORD_custom_props.docx", getParseContext()).metadata;
-
- assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- metadata.get(Metadata.CONTENT_TYPE));
- assertEquals("EJ04325S", metadata.get(TikaCoreProperties.CREATOR));
- assertEquals("Etienne Jouvin", metadata.get(TikaCoreProperties.MODIFIER));
- assertEquals("2011-07-29T16:52:00Z", metadata.get(TikaCoreProperties.CREATED));
- assertEquals("2012-01-03T22:14:00Z", metadata.get(TikaCoreProperties.MODIFIED));
- assertEquals("Microsoft Office Word", metadata.get(OfficeOpenXMLExtended.APPLICATION));
- assertEquals("1", metadata.get(Office.PAGE_COUNT));
- assertEquals("2", metadata.get(Office.WORD_COUNT));
- assertEquals("My Title", metadata.get(TikaCoreProperties.TITLE));
- assertEquals("My Keyword", metadata.get(Office.KEYWORDS));
- assertContains("My Keyword",
- Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
- assertEquals("Normal.dotm", metadata.get(OfficeOpenXMLExtended.TEMPLATE));
- assertEquals("My subject", metadata.get(DublinCore.SUBJECT));
- assertEquals("EDF-DIT", metadata.get(TikaCoreProperties.PUBLISHER));
- assertEquals("true", metadata.get("custom:myCustomBoolean"));
- assertEquals("3", metadata.get("custom:myCustomNumber"));
- assertEquals("MyStringValue", metadata.get("custom:MyCustomString"));
- assertEquals("2010-12-30T23:00:00Z", metadata.get("custom:MyCustomDate"));
- assertEquals("2010-12-29T22:00:00Z", metadata.get("custom:myCustomSecondDate"));
- }
-
- // TIKA-989:
- @Test
- public void testEmbeddedPDF() throws Exception {
- String xml = getXML("testWORD_embedded_pdf.docx", getParseContext()).xml;
- int i = xml.indexOf("Here is the pdf file:");
- int j = xml.indexOf("<div class=\"embedded\" id=\"rId5\" />");
- int k = xml.indexOf("Bye Bye");
- int l = xml.indexOf("<div class=\"embedded\" id=\"rId6\" />");
- int m = xml.indexOf("Bye for real.");
- assertTrue(i != -1);
- assertTrue(j != -1);
- assertTrue(k != -1);
- assertTrue(l != -1);
- assertTrue(m != -1);
- assertTrue(i < j);
- assertTrue(j < k);
- assertTrue(k < l);
- assertTrue(l < m);
- }
-
- // TIKA-1006
- @Test
- public void testWordNullStyle() throws Exception {
- String xml = getXML("testWORD_null_style.docx", getParseContext()).xml;
- assertContains("Test av styrt dokument", xml);
- }
-
- /**
- * TIKA-1044 - Handle word documents where parts of the
- * text have no formatting or styles applied to them
- */
- @Test
- public void testNoFormat() throws Exception {
- assertContains("This is a piece of text that causes an exception",
- getXML("testWORD_no_format.docx", getParseContext()).xml);
- }
-
- // TIKA-1005:
- @Test
- public void testTextInsideTextBox() throws Exception {
- String xml = getXML("testWORD_text_box.docx", getParseContext()).xml;
- assertContains("This text is directly in the body of the document.", xml);
- assertContains("This text is inside of a text box in the body of the document.", xml);
- assertContains("This text is inside of a text box in the header of the document.", xml);
- assertContains("This text is inside of a text box in the footer of the document.", xml);
- }
-
- //TIKA-2807
- @Test
- public void testSDTInTextBox() throws Exception {
- String xml = getXML("testWORD_sdtInTextBox.docx", getParseContext()).xml;
- assertContains("rich-text-content-control_inside-text-box", xml);
- assertContainsCount("inside-text", xml, 1);
- }
-
- @Test
- public void testDOCXOverrideParagraphNumbering() throws Exception {
- String xml = getXML("testWORD_override_list_numbering.docx", getParseContext()).xml;
-
- //Test 1
- assertContains("<p>1.1.1.1...1 1.1.1.1...1</p>", xml);
- assertContains("1st.2.3someText 1st.2.3someText", xml);
- assertContains("1st.2.2someOtherText.1 1st.2.2someOtherText.1", xml);
- assertContains("5th 5th", xml);
-
-
- //Test 2
- assertContains("1.a.I 1.a.I", xml);
- //test no reset because level 2 is not sufficient to reset
- assertContains("<p>1.b.III 1.b.III</p>", xml);
- //test restarted because of level 0's increment to 2
- assertContains("2.a.I 2.a.I", xml);
- //test handling of skipped level
- assertContains("<p>2.b 2.b</p>", xml);
-
- //Test 3
- assertContains("(1)) (1))", xml);
- //tests start level 1 at 17 and
- assertContains("2.17 2.17", xml);
- //tests that isLegal turns everything into decimal
- assertContains("2.18.2.1 2.18.2.1", xml);
- assertContains("<p>2 2</p>", xml);
-
- //Test4
- assertContains("<p>1 1</p>", xml);
- assertContains("<p>A A</p>", xml);
- assertContains("<p>B B</p>", xml);
- //this tests overrides
- assertContains("<p>C C</p>", xml);
- assertContains("<p>4 4</p>", xml);
-
- //Test5
- assertContains(">00 00", xml);
- assertContains(">01 01", xml);
- assertContains(">01. 01.", xml);
- assertContains(">01..1 01..1", xml);
- assertContains(">02 02", xml);
- }
-
- @Test
- public void testDiagramData() throws Exception {
- assertContains("From here",
- getXML("testWORD_diagramData.docx", getParseContext()).xml);
- }
-
- @Test
- public void testDOCXChartData() throws Exception {
- String xml = getXML("testWORD_charts.docx", getParseContext()).xml;
- assertContains("peach", xml);
- assertContains("March\tApril", xml);
- assertNotContained("chartSpace", xml);
- }
-
- @Test
- public void testDOCXPhoneticStrings() throws Exception {
- assertContains("\u6771\u4EAC (\u3068\u3046\u304D\u3087\u3046)",
- getXML("testWORD_phonetic.docx", getParseContext()).xml);
-
- OfficeParserConfig config = new OfficeParserConfig();
- config.setConcatenatePhoneticRuns(false);
- ParseContext parseContext = getParseContext();
- parseContext.set(OfficeParserConfig.class, config);
- String xml = getXML("testWORD_phonetic.docx", parseContext).xml;
- assertContains("\u6771\u4EAC", xml);
- assertNotContained("\u3068", xml);
- }
-
- @Test
- public void testVarious() throws Exception {
- Metadata metadata = new Metadata();
- String content = getText("testWORD_various.docx", metadata, getParseContext());
- //content = content.replaceAll("\\s+"," ");
- assertContains("Footnote appears here", content);
- assertContains("This is a footnote.", content);
- assertContains("This is the header text.", content);
- assertContains("This is the footer text.", content);
- assertContains("Here is a text box", content);
- assertContains("Bold", content);
- assertContains("italic", content);
- assertContains("underline", content);
- assertContains("superscript", content);
- assertContains("subscript", content);
- assertContains("Here is a citation:", content);
- assertContains("Figure 1 This is a caption for Figure 1", content);
- assertContains("(Kramer)", content);
- assertContains("Row 1 Col 1 Row 1 Col 2 Row 1 Col 3 Row 2 Col 1 Row 2 Col 2 Row 2 Col 3",
- content.replaceAll("\\s+", " "));
- assertContains("Row 1 column 1 Row 2 column 1 Row 1 column 2 Row 2 column 2",
- content.replaceAll("\\s+", " "));
- assertContains("This is a hyperlink", content);
- assertContains("Here is a list:", content);
- for (int row = 1; row <= 3; row++) {
- //assertContains("·\tBullet " + row, content);
- //assertContains("\u00b7\tBullet " + row, content);
- assertContains("Bullet " + row, content);
- }
- assertContains("Here is a numbered list:", content);
- for (int row = 1; row <= 3; row++) {
- //assertContains(row + ")\tNumber bullet " + row, content);
- //assertContains(row + ") Number bullet " + row, content);
- // TODO: OOXMLExtractor fails to number the bullets:
- assertContains("Number bullet " + row, content);
- }
-
- for (int row = 1; row <= 2; row++) {
- for (int col = 1; col <= 3; col++) {
- assertContains("Row " + row + " Col " + col, content);
- }
- }
-
- assertContains("Keyword1 Keyword2", content);
- assertEquals("Keyword1 Keyword2", metadata.get(Office.KEYWORDS));
- assertContains("Keyword1 Keyword2",
- Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
-
- assertContains("Subject is here", content);
- assertEquals("Subject is here", metadata.get(DublinCore.SUBJECT));
- assertContains("Subject is here",
- Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
-
- assertContains("Suddenly some Japanese text:", content);
- // Special version of (GHQ)
- assertContains("\uff08\uff27\uff28\uff31\uff09", content);
- // 6 other characters
- assertContains("\u30be\u30eb\u30b2\u3068\u5c3e\u5d0e\u3001\u6de1\u3005\u3068\u6700\u671f",
- content);
-
- assertContains("And then some Gothic text:", content);
- assertContains("\uD800\uDF32\uD800\uDF3f\uD800\uDF44\uD800\uDF39\uD800\uDF43\uD800\uDF3A",
- content);
- }
-
- /**
- * Test extraction of field-based hyperlinks using instrText/fldChar.
- * These are hyperlinks embedded as field codes rather than relationship-based hyperlinks.
- */
- @Test
- public void testInstrTextHyperlink() throws Exception {
- String xml = getXML("testInstrLink.docx", getParseContext()).xml;
- // The document contains a HYPERLINK field code in instrText
- assertContains("<a href=\"https://exmaple.com/file\">", xml);
- assertContains("Access Document(s)", xml);
- }
-
- /**
- * Test extraction of external reference field codes (INCLUDEPICTURE, INCLUDETEXT, IMPORT,
- * LINK).
- * These can be used to hide malicious URLs in documents.
- */
- @Test
- public void testExternalRefFieldCodes() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testExternalRefs.docx", getParseContext());
- Metadata m = metadataList.get(0);
- // Check metadata flag is set
- assertEquals("true", m.get(Office.HAS_FIELD_HYPERLINKS));
-
- String xml = getXML("testExternalRefs.docx", getParseContext()).xml;
- // Test INCLUDEPICTURE field code
- assertContains("class=\"external-ref-INCLUDEPICTURE\"", xml);
- assertContains("http://example.com/tracking.png", xml);
- // Test INCLUDETEXT field code
- assertContains("class=\"external-ref-INCLUDETEXT\"", xml);
- assertContains("http://example.org/payload.txt", xml);
- // Test IMPORT field code
- assertContains("class=\"external-ref-IMPORT\"", xml);
- assertContains("http://example.net/exploit.wmf", xml);
- // Test LINK field code
- assertContains("class=\"external-ref-LINK\"", xml);
- assertContains("http://test.invalid/cmd.docx", xml);
- }
-
- @Test
- public void testTextDecoration() throws Exception {
- String xml = getXML("testWORD_various.docx", getParseContext()).xml;
-
- assertContains("<b>Bold</b>", xml);
- assertContains("<i>italic</i>", xml);
- assertContains("<u>underline</u>", xml);
- assertContains("<s>strikethrough</s>", xml);
- }
-
- @Test
- public void testTextDecorationNested() throws Exception {
- String xml = getXML("testWORD_various.docx", getParseContext()).xml;
-
- assertContains("<i>ita<s>li</s>c</i>", xml);
- assertContains("<i>ita<s>l<u>i</u></s>c</i>", xml);
-
- String txt = getText("testWORD_various.docx", new Metadata(), getParseContext());
- assertContainsCount("italic", txt, 3);
- assertNotContained("ita ", txt);
-
- assertContainsCount("underline", txt, 2);
- assertNotContained("unde ", txt);
- }
-
- // TIKA-692
- @Test
- public void testContiguousHTMLFormatting() throws Exception {
- String xml = getXML("testWORD_bold_character_runs.docx", getParseContext()).xml;
- assertTrue(xml.contains("F<b>oob</b>a<b>r</b>"),
- "Bold text wasn't contiguous: " + xml);
-
- xml = getXML("testWORD_bold_character_runs2.docx", getParseContext()).xml;
- assertTrue(xml.contains("F<b>oob</b>a<b>r</b>"),
- "Bold text wasn't contiguous: " + xml);
- }
-
- //TIKA-2346
- @Test
- public void testTurningOffTextBoxExtraction() throws Exception {
- ParseContext pc = getParseContext();
- OfficeParserConfig config = getOrCreateOfficeParserConfig(pc);
- config.setIncludeShapeBasedContent(false);
- String xml = getXML("testWORD_text_box.docx", pc).xml;
- assertContains("This text is directly in the body of the document.", xml);
- assertNotContained(
- "This text is inside of a text box in the body of the document.", xml);
- assertNotContained(
- "This text is inside of a text box in the header of the document.", xml);
- assertNotContained(
- "This text is inside of a text box in the footer of the document.", xml);
- }
-
- @Test
- public void testHeaderFooterNotExtraction() throws Exception {
- ParseContext pc = getParseContext();
- OfficeParserConfig config = getOrCreateOfficeParserConfig(pc);
- config.setIncludeHeadersAndFooters(false);
- String xml = getXML("testWORD_various.docx", pc).xml;
- assertNotContained("This is the header text.", xml);
- assertNotContained("This is the footer text.", xml);
- }
-
- @Test
- public void testWordMissingOOXMLBeans() throws Exception {
- String[] fileNames = new String[]{"testWORD_missing_ooxml_bean1.docx"};
- PrintStream origErr = System.err;
- for (String fileName : fileNames) {
- ByteArrayOutputStream errContent = new ByteArrayOutputStream();
- System.setErr(new PrintStream(errContent, true, UTF_8.name()));
- getXML(fileName, getParseContext());
- System.setErr(origErr);
- String err = errContent.toString(UTF_8.name());
- assertTrue(err.isEmpty(),
- "expected no error msg, but got >" + err + "<");
- }
- }
-
-
- @Test
- public void testFeatureExtraction() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_features.docx", getParseContext());
- Metadata m = metadataList.get(0);
- assertContains("Kyle Reese", Arrays.asList(m.getValues(Office.COMMENT_PERSONS)));
- assertEquals("true", m.get(Office.HAS_HIDDEN_TEXT));
- assertEquals("true", m.get(Office.HAS_TRACK_CHANGES));
- assertEquals("true", m.get(Office.HAS_COMMENTS));
- }
-
- @Test
- public void testDotx() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_template.docx", getParseContext());
- String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
- assertContains("Metallica", content);
- assertContains("Hetfield", content);
- assertContains("one eye open", content);
- assertContains("Getting the perfect", content);
- }
-}
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/AbstractOOXMLPptxTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLPptxTest.java
deleted file mode 100644
index c2f79be3fe..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLPptxTest.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.xml.sax.ContentHandler;
-
-import org.apache.tika.TikaTest;
-import org.apache.tika.io.TikaInputStream;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
-import org.apache.tika.sax.BodyContentHandler;
-
-public abstract class AbstractOOXMLPptxTest extends TikaTest {
-
- abstract ParseContext getParseContext();
-
- protected OfficeParserConfig getOrCreateOfficeParserConfig(ParseContext parseContext) {
- OfficeParserConfig config = parseContext.get(OfficeParserConfig.class);
- if (config == null) {
- config = new OfficeParserConfig();
- parseContext.set(OfficeParserConfig.class, config);
- }
- return config;
- }
-
- /**
- * We have a number of different powerpoint files,
- * such as presentation, macro-enabled etc
- */
- @Test
- public void testPowerPoint() throws Exception {
- String[] extensions = new String[]{"pptx", "pptm", "ppsm", "ppsx", "potm"
- //"thmx", // TIKA-418: Will be supported in POI 3.7 beta 2
- //"xps" // TIKA-418: Not yet supported by POI
- };
-
- String[] mimeTypes = new String[]{
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
- "application/vnd.ms-powerpoint.presentation.macroenabled.12",
- "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
- "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
- "application/vnd.ms-powerpoint.template.macroenabled.12"};
-
- for (int i = 0; i < extensions.length; i++) {
- String extension = extensions[i];
- String filename = "testPPT." + extension;
-
- Metadata metadata = new Metadata();
- ContentHandler handler = new BodyContentHandler();
-
- try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
- AUTO_DETECT_PARSER.parse(tis, handler, metadata, getParseContext());
-
- assertEquals(mimeTypes[i], metadata.get(Metadata.CONTENT_TYPE),
- "Mime-type checking for " + filename);
- assertEquals("Attachment Test", metadata.get(TikaCoreProperties.TITLE));
- assertEquals("Rajiv", metadata.get(TikaCoreProperties.CREATOR));
-
- String content = handler.toString();
- // Theme files don't have the text in them
- if (extension.equals("thmx")) {
- assertEquals("", content);
- } else {
- assertTrue(content.contains("Attachment Test"),
- "Text missing for " + filename + "\n" + content);
- assertTrue(content.contains("This is a test file data with the same content"),
- "Text missing for " + filename + "\n" + content);
- assertTrue(content.contains("content parsing"),
- "Text missing for " + filename + "\n" + content);
- assertTrue(content.contains("Different words to test against"),
- "Text missing for " + filename + "\n" + content);
- assertTrue(content.contains("Mystery"),
- "Text missing for " + filename + "\n" + content);
- }
- }
- }
- }
-
- /**
- * Test that the metadata is already extracted when the body is processed.
- * See TIKA-1109
- */
- @Test
- public void testPowerPointMetadataEarly() throws Exception {
- String[] extensions = new String[]{"pptx", "pptm", "ppsm", "ppsx", "potm"
- //"thmx", // TIKA-418: Will be supported in POI 3.7 beta 2
- //"xps" // TIKA-418: Not yet supported by POI
- };
-
- final String[] mimeTypes = new String[]{
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
- "application/vnd.ms-powerpoint.presentation.macroenabled.12",
- "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
- "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
- "application/vnd.ms-powerpoint.template.macroenabled.12"};
-
- for (int i = 0; i < extensions.length; i++) {
- String extension = extensions[i];
- final String filename = "testPPT." + extension;
- final Metadata metadata = new Metadata();
-
- // Allow the value to be access from the inner class
- final int currentI = i;
- ContentHandler handler = new BodyContentHandler() {
- public void startDocument() {
- assertEquals(mimeTypes[currentI], metadata.get(Metadata.CONTENT_TYPE),
- "Mime-type checking for " + filename);
- assertEquals("Attachment Test", metadata.get(TikaCoreProperties.TITLE));
- assertEquals("Rajiv", metadata.get(TikaCoreProperties.CREATOR));
-
- }
-
- };
-
- try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
- AUTO_DETECT_PARSER.parse(tis, handler, metadata, getParseContext());
- }
- }
- }
-
- /**
- * For the PowerPoint formats we don't currently support, ensure that
- * we don't break either
- */
- @Test
- public void testUnsupportedPowerPoint() throws Exception {
- String[] extensions = new String[]{"xps", "thmx"};
- String[] mimeTypes = new String[]{"application/vnd.ms-xpsdocument",
- "application/vnd.openxmlformats-officedocument" // Is this right?
- };
-
- for (int i = 0; i < extensions.length; i++) {
- String extension = extensions[i];
- String filename = "testPPT." + extension;
-
- Metadata metadata = new Metadata();
- metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, filename);
- ContentHandler handler = new BodyContentHandler();
-
- try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
- AUTO_DETECT_PARSER.parse(tis, handler, metadata, getParseContext());
-
- // Should get the metadata
- assertEquals(mimeTypes[i], metadata.get(Metadata.CONTENT_TYPE),
- "Mime-type checking for " + filename);
-
- // But that's about it
- }
- }
- }
-
- @Test
- public void testVariousPPTX() throws Exception {
- Metadata metadata = new Metadata();
- String xml = getXML("testPPT_various.pptx", metadata, getParseContext()).xml;
- assertContains("<p>Footnote appears here", xml);
- assertContains("<p>[1] This is a footnote.", xml);
- assertContains("<p>This is the header text.</p>", xml);
- assertContains("<p>This is the footer text.</p>", xml);
- assertContains("<p>Here is a text box</p>", xml);
- assertContains("<p>Bold", xml);
- assertContains("italic underline superscript subscript", xml);
- assertContains("<p>Here is a citation:", xml);
- assertContains("Figure 1 This is a caption for Figure 1", xml);
- assertContains("(Kramer)", xml);
- assertContains("<table><tr>\t<td>Row 1 Col 1</td>", xml);
- assertContains("<td>Row 2 Col 2</td>\t<td>Row 2 Col 3</td></tr>", xml);
- assertContains("<p>Row 1 column 1</p>", xml);
- assertContains("<p>Row 2 column 2</p>", xml);
- assertContains("<p><a href=\"http://tika.apache.org/\">This is a hyperlink</a>", xml);
- assertContains("<p>Here is a list:", xml);
- for (int row = 1; row <= 3; row++) {
- assertContains("<p>Bullet " + row, xml);
- }
- assertContains("Here is a numbered list:", xml);
- for (int row = 1; row <= 3; row++) {
- assertContains("<p>Number bullet " + row, xml);
- }
-
- for (int row = 1; row <= 2; row++) {
- for (int col = 1; col <= 3; col++) {
- assertContains("Row " + row + " Col " + col, xml);
- }
- }
-
- assertContains("Keyword1 Keyword2", xml);
- assertEquals("Keyword1 Keyword2", metadata.get(Office.KEYWORDS));
-
- assertContains("Subject is here", xml);
-
- assertContains("Suddenly some Japanese text:", xml);
- // Special version of (GHQ)
- assertContains("\uff08\uff27\uff28\uff31\uff09", xml);
- // 6 other characters
- assertContains("\u30be\u30eb\u30b2\u3068\u5c3e\u5d0e\u3001\u6de1\u3005\u3068\u6700\u671f",
- xml);
-
- assertContains("And then some Gothic text:", xml);
- assertContains("\uD800\uDF32\uD800\uDF3f\uD800\uDF44\uD800\uDF39\uD800\uDF43\uD800\uDF3A",
- xml);
- }
-
- @Test
- public void testCommentPPTX() throws Exception {
- XMLResult r = getXML("testPPT_comment.pptx", getParseContext());
- assertContains("<p class=\"slide-comment\"><b>Allison, Timothy B. (ATB)", r.xml);
- }
-
- @Test
- public void testMasterFooter() throws Exception {
- assertContains("Master footer is here",
- getXML("testPPT_masterFooter.pptx", getParseContext()).xml);
- }
-
- @Test
- @Disabled("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.
- ParseContext context = getParseContext();
- OfficeParserConfig config = getOrCreateOfficeParserConfig(context);
- config.setIncludeSlideMasterContent(false);
- 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
- */
- @Test
- public void testMasterText() throws Exception {
- assertContains("Text that I added to the master slide",
- getXML("testPPT_masterText.pptx", getParseContext()).xml);
-
- //now test turning off master content
- ParseContext context = getParseContext();
- OfficeParserConfig config = getOrCreateOfficeParserConfig(context);
- config.setIncludeSlideMasterContent(false);
-
- 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", getParseContext()).xml);
-
- //now test turning off master content
- ParseContext context = getParseContext();
- OfficeParserConfig config = getOrCreateOfficeParserConfig(context);
- config.setIncludeSlideMasterContent(false);
-
- assertNotContained("Text that I added",
- getXML("testPPT_masterText2.pptx", context).xml);
- }
-
- @Test
- public void testWordArt() throws Exception {
- assertContains("Here is some red word Art",
- getXML("testWordArt.pptx", getParseContext()).xml);
- }
-
- //TIKA-817
- @Test
- public void testPPTXAutodate() throws Exception {
- //Following POI-52368, the stored date is extracted,
- //not the auto-generated date.
-
- XMLResult result = getXML("testPPT_autodate.pptx", getParseContext());
- assertContains("<p>Now</p>\n" + "<p>2011-12-19 10:20:04 AM</p>\n", result.xml);
- }
-
- @Test
- public void testPPTXThumbnail() throws Exception {
- String xml = getXML("testPPTX_Thumbnail.pptx", getParseContext()).xml;
- int a = xml.indexOf(
- "<body><div class=\"slide-content\"><p>This file contains an embedded thumbnail");
- int b = xml.indexOf("<div class=\"embedded\" id=\"/docProps/thumbnail.jpeg\" />");
- assertTrue(a != -1);
- assertTrue(b != -1);
- assertTrue(a < b);
- }
-
- @Test
- public void testPPTXDiagramData() throws Exception {
- assertContains("President",
- getXML("testPPT_diagramData.pptx", getParseContext()).xml);
- }
-
- @Test
- public void testPPTXChartData() throws Exception {
- String xml = getXML("testPPT_charts.pptx", getParseContext()).xml;
- assertContains("peach", xml);
- assertContains("March\tApril", xml);
- assertNotContained("chartSpace", xml);
- }
-
- @Test
- public void testPPTXGroups() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_groups.pptx", getParseContext());
- assertEquals(3, metadataList.size());
- String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
- assertContains("WordArt1", content);
- assertContains("WordArt2", content);
- assertContainsCount("Ungrouped text box", content, 1);//should only be 1
- assertContains("Text box1", content);
- assertContains("Text box2", content);
- assertContains("Text box3", content);
- assertContains("Text box4", content);
- assertContains("Text box5", content);
-
- assertContains("href=\"http://tika.apache.org", content);
- assertContains("smart1", content);
- assertContains("MyTitle", content);
-
- assertEquals("/image1.jpg",
- metadataList.get(1).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
-
- assertEquals("/thumbnail.jpeg",
- metadataList.get(2).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
- }
-
- @Test
- public void testEmbeddedMedia() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_embeddedMP3.pptx", getParseContext());
- assertEquals(4, metadataList.size());
- assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation",
- metadataList.get(0).get(Metadata.CONTENT_TYPE));
- assertEquals("audio/mpeg", metadataList.get(1).get(Metadata.CONTENT_TYPE));
- assertEquals("image/png", metadataList.get(2).get(Metadata.CONTENT_TYPE));
- assertEquals("image/jpeg", metadataList.get(3).get(Metadata.CONTENT_TYPE));
- }
-}
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/OOXMLDocxDOMTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxDOMTest.java
deleted file mode 100644
index 5d9fd42ec6..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxDOMTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.tika.config.loader.TikaLoader;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.AutoDetectParser;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
-import org.apache.tika.parser.microsoft.OfficeParserTest;
-
-/**
- * Runs the shared DOCX tests using the DOM-based parser (default),
- * plus DOM-specific tests.
- */
-public class OOXMLDocxDOMTest extends AbstractOOXMLDocxTest {
-
- @Override
- ParseContext getParseContext() {
- return new ParseContext();
- }
-
- @Test
- public void testTextDecorationNestedUnderlineStrike() throws Exception {
- // DOM nests s inside u: <u>unde<s>r</s>line</u>
- String xml = getXML("testWORD_various.docx", getParseContext()).xml;
- assertContains("<i><u>unde<s>r</s>line</u></i>", xml);
- }
-
- @Test
- public void testDOCXHeaderFooterNotExtractionViaConfig() throws Exception {
- // Test configuration via tika-config
- AutoDetectParser configuredParser = (AutoDetectParser) TikaLoader.load(
- getConfigPath(OfficeParserTest.class, "tika-config-headers-footers.json"))
- .loadAutoDetectParser();
- String xml = getXML("testWORD_various.docx", configuredParser).xml;
- assertNotContained("This is the header text.", xml);
- assertNotContained("This is the footer text.", xml);
- }
-
- @Test
- public void testDOCXParagraphNumbering() throws Exception {
- String xml = getXML("testWORD_numbered_list.docx", getParseContext()).xml;
- assertContains("1) This", xml);
- assertContains("a) Is", xml);
- assertContains("i) A multi", xml);
- assertContains("ii) Level", xml);
- assertContains("1. Within cell 1", xml);
- assertContains("b. Cell b", xml);
- assertContains("iii) List", xml);
- assertContains("2) foo", xml);
- assertContains("ii) baz", xml);
- assertContains("ii) foo", xml);
- assertContains("II. bar", xml);
- assertContains("6. six", xml);
- assertContains("7. seven", xml);
- assertContains("a. seven a", xml);
- assertContains("e. seven e", xml);
- assertContains("2. A ii 2", xml);
- assertContains("3. page break list 3", xml);
- assertContains("Some-1-CrazyFormat Greek numbering with crazy format - alpha", xml);
- assertContains("1.1.1. 1.1.1", xml);
- assertContains("1.1. 1.2->1.1 //set the value", xml);
- }
-
- @Test
- public void testMacrosInDocm() throws Exception {
- //test default is "don't extract macros"
- for (Metadata metadata : getRecursiveMetadata("testWORD_macros.docm", getParseContext())) {
- if (metadata.get(Metadata.CONTENT_TYPE).equals("text/x-vbasic")) {
- fail("Shouldn't have extracted macros as default");
- }
- }
-
- //now test that they were extracted
- ParseContext context = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setExtractMacros(true);
- context.set(OfficeParserConfig.class, officeParserConfig);
-
- Metadata minExpected = new Metadata();
- minExpected.add(TikaCoreProperties.TIKA_CONTENT.getName(), "Sub Embolden()");
- minExpected.add(TikaCoreProperties.TIKA_CONTENT.getName(), "Sub Italicize()");
- minExpected.add(Metadata.CONTENT_TYPE, "text/x-vbasic");
- minExpected.add(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE,
- TikaCoreProperties.EmbeddedResourceType.MACRO.toString());
-
- assertContainsAtLeast(minExpected,
- getRecursiveMetadata("testWORD_macros.docm", context));
-
- //test configuring via config file
- AutoDetectParser parser = (AutoDetectParser) TikaLoader.load(
- getConfigPath(OOXMLParserTest.class, "tika-config-dom-macros.json"))
- .loadAutoDetectParser();
- assertContainsAtLeast(minExpected,
- getRecursiveMetadata("testWORD_macros.docm", parser));
- }
-
- @Test
- public void testEmbedded() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_embeded.docx", getParseContext());
- Metadata main = metadataList.get(0);
- String content = main.get(TikaCoreProperties.TIKA_CONTENT);
- assertContains(
- "<img src=\"embedded:image2.jpeg\" alt=\"A description...\" />", content);
- assertContains("<div class=\"embedded\" id=\"rId8\" />", content);
- assertEquals(16, metadataList.size());
- }
-
-}
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/OOXMLDocxSAXTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java
index ac533400e0..173922f388 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXTest.java
@@ -16,21 +16,27 @@
*/
package org.apache.tika.parser.microsoft.ooxml;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.apache.tika.TikaTest;
import org.apache.tika.config.loader.TikaLoader;
import org.apache.tika.exception.EncryptedDocumentException;
import org.apache.tika.exception.TikaException;
import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.DublinCore;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.Office;
import org.apache.tika.metadata.OfficeOpenXMLCore;
@@ -42,31 +48,465 @@ import org.apache.tika.parser.PasswordProvider;
import org.apache.tika.parser.microsoft.OfficeParserConfig;
/**
- * Runs the shared DOCX tests using the SAX-based streaming parser,
- * plus SAX-specific tests (security features, deleted content, etc.).
+ * Tests for the DOCX parser.
*/
-public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
+public class OOXMLDocxSAXTest extends TikaTest {
- @Override
- ParseContext getParseContext() {
+ // ---- tests from AbstractOOXMLDocxTest ----
+
+ @Test
+ public void testWord() throws Exception {
+ XMLResult xmlResult = getXML("testWORD.docx");
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ xmlResult.metadata.get(Metadata.CONTENT_TYPE));
+ assertEquals("Sample Word Document", xmlResult.metadata.get(TikaCoreProperties.TITLE));
+ assertEquals("Keith Bennett", xmlResult.metadata.get(TikaCoreProperties.CREATOR));
+ assertTrue(xmlResult.xml.contains("Sample Word Document"));
+ }
+
+ @Test
+ public void testWordFootnote() throws Exception {
+ XMLResult xmlResult = getXML("footnotes.docx");
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ xmlResult.metadata.get(Metadata.CONTENT_TYPE));
+ assertTrue(xmlResult.xml.contains("snoska"));
+ assertContains("<div class=\"footnote\">", xmlResult.xml);
+ assertNotContained("<p><div class=\"footnote\">", xmlResult.xml);
+ }
+
+ @Test
+ public void testEndnoteWithTable() throws Exception {
+ XMLResult xmlResult = getXML("testWORD_endnote_table.docx");
+ assertContains("Cat Property Act", xmlResult.xml);
+ assertContains("<div class=\"endnote\">", xmlResult.xml);
+ }
+
+ @Test
+ public void testWordHTML() throws Exception {
+ XMLResult result = getXML("testWORD.docx");
+ String xml = result.xml;
+ Metadata metadata = result.metadata;
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ metadata.get(Metadata.CONTENT_TYPE));
+ assertEquals("Sample Word Document", metadata.get(TikaCoreProperties.TITLE));
+ assertEquals("Keith Bennett", metadata.get(TikaCoreProperties.CREATOR));
+ assertTrue(xml.contains("Sample Word Document"));
+ assertTrue(xml.contains("<h1 class=\"title\">"));
+ assertContains("<h1>Heading Level 1</h1>", xml);
+ assertTrue(xml.contains("<h2>Heading Level 2</h2>"));
+ assertContains("Heading Level 3", xml);
+ assertContains("<a name=\"OnLevel3\" />", xml);
+ assertTrue(xml.contains("<b>BOLD</b>"));
+ assertTrue(xml.contains("<i>ITALIC</i>"));
+ assertTrue(xml.contains("<table>"));
+ assertTrue(xml.contains("<td>"));
+ assertTrue(xml.contains("<a href=\"http://tika.apache.org/\">Tika</a>"));
+ assertContains("<a href=\"#OnMainHeading\">The Main Heading Bookmark</a>", xml);
+ assertTrue(xml.contains("<p class=\"signature\">This one"));
+
+ result = getXML("testWORD_3imgs.docx");
+ xml = result.xml;
+
+ assertTrue(xml.contains("<img src=\"embedded:image2.png\" alt=\"A description...\" />"),
+ "Image not found in:\n" + xml);
+ assertTrue(xml.contains("<img src=\"embedded:image3.jpeg\" alt=\"A description...\" />"),
+ "Image not found in:\n" + xml);
+ assertTrue(xml.contains("<img src=\"embedded:image4.png\" alt=\"A description...\" />"),
+ "Image not found in:\n" + xml);
+ assertTrue(xml.contains("<p>The end!</p>"));
+ }
+
+ @Test
+ public void testWordPicturesInHeader() throws Exception {
+ List<Metadata> metadataList = getRecursiveMetadata("headerPic.docx");
+ assertEquals(2, metadataList.size());
+ Metadata m = metadataList.get(0);
+ String mainContent = m.get(TikaCoreProperties.TIKA_CONTENT);
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ m.get(Metadata.CONTENT_TYPE));
+ assertTrue(mainContent.contains("<img"));
+ }
+
+ @Test
+ public void testNullHeaders() throws Exception {
+ XMLResult xmlResult = getXML("NullHeader.docx");
+ assertEquals(false, xmlResult.xml.isEmpty(), "Should have found some text");
+ }
+
+ @Test
+ public void testMissingText() throws Exception {
+ XMLResult xmlResult = getXML("testWORD_missing_text.docx");
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ xmlResult.metadata.get(Metadata.CONTENT_TYPE));
+ assertContains("BigCompany", xmlResult.xml);
+ assertContains("Seasoned", xmlResult.xml);
+ assertContains("Rich_text_in_cell", xmlResult.xml);
+ }
+
+ @Test
+ public void testBoldHyperlink() throws Exception {
+ String xml = getXML("testWORD_boldHyperlink.docx").xml;
+ xml = xml.replaceAll("\\s+", " ");
+ assertContains("<a href=\"http://tika.apache.org/\">hyper <b>link</b></a>", xml);
+ assertContains("<a href=\"http://tika.apache.org/\"><b>hyper</b> link</a>; bold", xml);
+ }
+
+ @Test
+ public void testLongForIntExceptionInSummaryDetails() throws Exception {
+ assertContains("bold",
+ getXML("testWORD_totalTimeOutOfRange.docx").xml);
+ }
+
+ @Test
+ public void testMultiAuthorsManagers() throws Exception {
+ XMLResult r = getXML("testWORD_multi_authors.docx");
+ String[] authors = r.metadata.getValues(TikaCoreProperties.CREATOR);
+ assertEquals(3, authors.length);
+ assertEquals("author2", authors[1]);
+ String[] managers = r.metadata.getValues(OfficeOpenXMLExtended.MANAGER);
+ assertEquals(2, managers.length);
+ assertEquals("manager1", managers[0]);
+ assertEquals("manager2", managers[1]);
+ }
+
+ @Test
+ public void testOrigSourcePath() throws Exception {
+ Metadata embed1_zip_metadata =
+ getRecursiveMetadata("test_recursive_embedded.docx").get(2);
+ assertContains("C:\\Users\\tallison\\AppData\\Local\\Temp\\embed1.zip", Arrays.asList(
+ embed1_zip_metadata.getValues(TikaCoreProperties.ORIGINAL_RESOURCE_NAME)));
+ assertContains("C:\\Users\\tallison\\Desktop\\tmp\\New folder (2)\\embed1.zip",
+ Arrays.asList(
+ embed1_zip_metadata.getValues(
+ TikaCoreProperties.ORIGINAL_RESOURCE_NAME)));
+ }
+
+ @Test
+ public void testDOCXThumbnail() throws Exception {
+ String xml = getXML("testDOCX_Thumbnail.docx").xml;
+ int a = xml.indexOf("This file contains a thumbnail");
+ int b = xml.indexOf("<div class=\"embedded\" id=\"/docProps/thumbnail.emf\" />");
+ assertTrue(a != -1);
+ assertTrue(b != -1);
+ assertTrue(a < b);
+ }
+
+ @Test
+ public void testWordCustomProperties() throws Exception {
+ Metadata metadata = getXML("testWORD_custom_props.docx").metadata;
+ assertEquals("application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ metadata.get(Metadata.CONTENT_TYPE));
+ assertEquals("EJ04325S", metadata.get(TikaCoreProperties.CREATOR));
+ assertEquals("Etienne Jouvin", metadata.get(TikaCoreProperties.MODIFIER));
+ assertEquals("2011-07-29T16:52:00Z", metadata.get(TikaCoreProperties.CREATED));
+ assertEquals("2012-01-03T22:14:00Z", metadata.get(TikaCoreProperties.MODIFIED));
+ assertEquals("Microsoft Office Word", metadata.get(OfficeOpenXMLExtended.APPLICATION));
+ assertEquals("1", metadata.get(Office.PAGE_COUNT));
+ assertEquals("2", metadata.get(Office.WORD_COUNT));
+ assertEquals("My Title", metadata.get(TikaCoreProperties.TITLE));
+ assertEquals("My Keyword", metadata.get(Office.KEYWORDS));
+ assertContains("My Keyword",
+ Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
+ assertEquals("Normal.dotm", metadata.get(OfficeOpenXMLExtended.TEMPLATE));
+ assertEquals("My subject", metadata.get(DublinCore.SUBJECT));
+ assertEquals("EDF-DIT", metadata.get(TikaCoreProperties.PUBLISHER));
+ assertEquals("true", metadata.get("custom:myCustomBoolean"));
+ assertEquals("3", metadata.get("custom:myCustomNumber"));
+ assertEquals("MyStringValue", metadata.get("custom:MyCustomString"));
+ assertEquals("2010-12-30T23:00:00Z", metadata.get("custom:MyCustomDate"));
+ assertEquals("2010-12-29T22:00:00Z", metadata.get("custom:myCustomSecondDate"));
+ }
+
+ @Test
+ public void testEmbeddedPDF() throws Exception {
+ String xml = getXML("testWORD_embedded_pdf.docx").xml;
+ int i = xml.indexOf("Here is the pdf file:");
+ int j = xml.indexOf("<div class=\"embedded\" id=\"rId5\" />");
+ int k = xml.indexOf("Bye Bye");
+ int l = xml.indexOf("<div class=\"embedded\" id=\"rId6\" />");
+ int m = xml.indexOf("Bye for real.");
+ assertTrue(i != -1);
+ assertTrue(j != -1);
+ assertTrue(k != -1);
+ assertTrue(l != -1);
+ assertTrue(m != -1);
+ assertTrue(i < j);
+ assertTrue(j < k);
+ assertTrue(k < l);
+ assertTrue(l < m);
+ }
+
+ @Test
+ public void testWordNullStyle() throws Exception {
+ String xml = getXML("testWORD_null_style.docx").xml;
+ assertContains("Test av styrt dokument", xml);
+ }
+
+ @Test
+ public void testNoFormat() throws Exception {
+ assertContains("This is a piece of text that causes an exception",
+ getXML("testWORD_no_format.docx").xml);
+ }
+
+ @Test
+ public void testTextInsideTextBox() throws Exception {
+ String xml = getXML("testWORD_text_box.docx").xml;
+ assertContains("This text is directly in the body of the document.", xml);
+ assertContains("This text is inside of a text box in the body of the document.", xml);
+ assertContains("This text is inside of a text box in the header of the document.", xml);
+ assertContains("This text is inside of a text box in the footer of the document.", xml);
+ }
+
+ @Test
+ public void testSDTInTextBox() throws Exception {
+ String xml = getXML("testWORD_sdtInTextBox.docx").xml;
+ assertContains("rich-text-content-control_inside-text-box", xml);
+ assertContainsCount("inside-text", xml, 1);
+ }
+
+ @Test
+ public void testDOCXOverrideParagraphNumbering() throws Exception {
+ String xml = getXML("testWORD_override_list_numbering.docx").xml;
+
+ assertContains("<p>1.1.1.1...1 1.1.1.1...1</p>", xml);
+ assertContains("1st.2.3someText 1st.2.3someText", xml);
+ assertContains("1st.2.2someOtherText.1 1st.2.2someOtherText.1", xml);
+ assertContains("5th 5th", xml);
+
+ assertContains("1.a.I 1.a.I", xml);
+ assertContains("<p>1.b.III 1.b.III</p>", xml);
+ assertContains("2.a.I 2.a.I", xml);
+ assertContains("<p>2.b 2.b</p>", xml);
+
+ assertContains("(1)) (1))", xml);
+ assertContains("2.17 2.17", xml);
+ assertContains("2.18.2.1 2.18.2.1", xml);
+ assertContains("<p>2 2</p>", xml);
+
+ assertContains("<p>1 1</p>", xml);
+ assertContains("<p>A A</p>", xml);
+ assertContains("<p>B B</p>", xml);
+ assertContains("<p>C C</p>", xml);
+ assertContains("<p>4 4</p>", xml);
+
+ assertContains(">00 00", xml);
+ assertContains(">01 01", xml);
+ assertContains(">01. 01.", xml);
+ assertContains(">01..1 01..1", xml);
+ assertContains(">02 02", xml);
+ }
+
+ @Test
+ public void testDiagramData() throws Exception {
+ assertContains("From here",
+ getXML("testWORD_diagramData.docx").xml);
+ }
+
+ @Test
+ public void testDOCXChartData() throws Exception {
+ String xml = getXML("testWORD_charts.docx").xml;
+ assertContains("peach", xml);
+ assertContains("March\tApril", xml);
+ assertNotContained("chartSpace", xml);
+ }
+
+ @Test
+ public void testDOCXPhoneticStrings() throws Exception {
+ assertContains("\u6771\u4EAC (\u3068\u3046\u304D\u3087\u3046)",
+ getXML("testWORD_phonetic.docx").xml);
+
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setConcatenatePhoneticRuns(false);
ParseContext parseContext = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setUseSAXDocxExtractor(true);
- parseContext.set(OfficeParserConfig.class, officeParserConfig);
- return parseContext;
+ parseContext.set(OfficeParserConfig.class, config);
+ String xml = getXML("testWORD_phonetic.docx", parseContext).xml;
+ assertContains("\u6771\u4EAC", xml);
+ assertNotContained("\u3068", xml);
+ }
+
+ @Test
+ public void testVarious() throws Exception {
+ Metadata metadata = new Metadata();
+ String content = getText("testWORD_various.docx", metadata);
+ assertContains("Footnote appears here", content);
+ assertContains("This is a footnote.", content);
+ assertContains("This is the header text.", content);
+ assertContains("This is the footer text.", content);
+ assertContains("Here is a text box", content);
+ assertContains("Bold", content);
+ assertContains("italic", content);
+ assertContains("underline", content);
+ assertContains("superscript", content);
+ assertContains("subscript", content);
+ assertContains("Here is a citation:", content);
+ assertContains("Figure 1 This is a caption for Figure 1", content);
+ assertContains("(Kramer)", content);
+ assertContains("Row 1 Col 1 Row 1 Col 2 Row 1 Col 3 Row 2 Col 1 Row 2 Col 2 Row 2 Col 3",
+ content.replaceAll("\\s+", " "));
+ assertContains("Row 1 column 1 Row 2 column 1 Row 1 column 2 Row 2 column 2",
+ content.replaceAll("\\s+", " "));
+ assertContains("This is a hyperlink", content);
+ assertContains("Here is a list:", content);
+ for (int row = 1; row <= 3; row++) {
+ assertContains("Bullet " + row, content);
+ }
+ assertContains("Here is a numbered list:", content);
+ for (int row = 1; row <= 3; row++) {
+ assertContains("Number bullet " + row, content);
+ }
+ for (int row = 1; row <= 2; row++) {
+ for (int col = 1; col <= 3; col++) {
+ assertContains("Row " + row + " Col " + col, content);
+ }
+ }
+ assertContains("Keyword1 Keyword2", content);
+ assertEquals("Keyword1 Keyword2", metadata.get(Office.KEYWORDS));
+ assertContains("Keyword1 Keyword2",
+ Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
+ assertContains("Subject is here", content);
+ assertEquals("Subject is here", metadata.get(DublinCore.SUBJECT));
+ assertContains("Subject is here",
+ Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
+ assertContains("Suddenly some Japanese text:", content);
+ assertContains("\uff08\uff27\uff28\uff31\uff09", content);
+ assertContains("\u30be\u30eb\u30b2\u3068\u5c3e\u5d0e\u3001\u6de1\u3005\u3068\u6700\u671f",
+ content);
+ assertContains("And then some Gothic text:", content);
+ assertContains("\uD800\uDF32\uD800\uDF3f\uD800\uDF44\uD800\uDF39\uD800\uDF43\uD800\uDF3A",
+ content);
+ }
+
+ @Test
+ public void testInstrTextHyperlink() throws Exception {
+ String xml = getXML("testInstrLink.docx").xml;
+ assertContains("<a href=\"https://exmaple.com/file\">", xml);
+ assertContains("Access Document(s)", xml);
+ }
+
+ @Test
+ public void testExternalRefFieldCodes() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testExternalRefs.docx");
+ Metadata m = metadataList.get(0);
+ assertEquals("true", m.get(Office.HAS_FIELD_HYPERLINKS));
+ String xml = getXML("testExternalRefs.docx").xml;
+ assertContains("class=\"external-ref-INCLUDEPICTURE\"", xml);
+ assertContains("http://example.com/tracking.png", xml);
+ assertContains("class=\"external-ref-INCLUDETEXT\"", xml);
+ assertContains("http://example.org/payload.txt", xml);
+ assertContains("class=\"external-ref-IMPORT\"", xml);
+ assertContains("http://example.net/exploit.wmf", xml);
+ assertContains("class=\"external-ref-LINK\"", xml);
+ assertContains("http://test.invalid/cmd.docx", xml);
+ }
+
+ @Test
+ public void testTextDecoration() throws Exception {
+ String xml = getXML("testWORD_various.docx").xml;
+ assertContains("<b>Bold</b>", xml);
+ assertContains("<i>italic</i>", xml);
+ assertContains("<u>underline</u>", xml);
+ assertContains("<s>strikethrough</s>", xml);
}
+ @Test
+ public void testTextDecorationNested() throws Exception {
+ String xml = getXML("testWORD_various.docx").xml;
+ assertContains("<i>ita<s>li</s>c</i>", xml);
+ assertContains("<i>ita<s>l<u>i</u></s>c</i>", xml);
+ String txt = getText("testWORD_various.docx");
+ assertContainsCount("italic", txt, 3);
+ assertNotContained("ita ", txt);
+ assertContainsCount("underline", txt, 2);
+ assertNotContained("unde ", txt);
+ }
+
+ @Test
+ public void testContiguousHTMLFormatting() throws Exception {
+ String xml = getXML("testWORD_bold_character_runs.docx").xml;
+ assertTrue(xml.contains("F<b>oob</b>a<b>r</b>"),
+ "Bold text wasn't contiguous: " + xml);
+ xml = getXML("testWORD_bold_character_runs2.docx").xml;
+ assertTrue(xml.contains("F<b>oob</b>a<b>r</b>"),
+ "Bold text wasn't contiguous: " + xml);
+ }
+
+ @Test
+ public void testTurningOffTextBoxExtraction() throws Exception {
+ ParseContext pc = new ParseContext();
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setIncludeShapeBasedContent(false);
+ pc.set(OfficeParserConfig.class, config);
+ String xml = getXML("testWORD_text_box.docx", pc).xml;
+ assertContains("This text is directly in the body of the document.", xml);
+ assertNotContained(
+ "This text is inside of a text box in the body of the document.", xml);
+ assertNotContained(
+ "This text is inside of a text box in the header of the document.", xml);
+ assertNotContained(
+ "This text is inside of a text box in the footer of the document.", xml);
+ }
+
+ @Test
+ public void testHeaderFooterNotExtraction() throws Exception {
+ ParseContext pc = new ParseContext();
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setIncludeHeadersAndFooters(false);
+ pc.set(OfficeParserConfig.class, config);
+ String xml = getXML("testWORD_various.docx", pc).xml;
+ assertNotContained("This is the header text.", xml);
+ assertNotContained("This is the footer text.", xml);
+ }
+
+ @Test
+ public void testWordMissingOOXMLBeans() throws Exception {
+ String[] fileNames = new String[]{"testWORD_missing_ooxml_bean1.docx"};
+ PrintStream origErr = System.err;
+ for (String fileName : fileNames) {
+ ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+ System.setErr(new PrintStream(errContent, true, UTF_8.name()));
+ getXML(fileName);
+ System.setErr(origErr);
+ String err = errContent.toString(UTF_8.name());
+ assertTrue(err.isEmpty(),
+ "expected no error msg, but got >" + err + "<");
+ }
+ }
+
+ @Test
+ public void testFeatureExtraction() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testWORD_features.docx");
+ Metadata m = metadataList.get(0);
+ assertContains("Kyle Reese", Arrays.asList(m.getValues(Office.COMMENT_PERSONS)));
+ assertEquals("true", m.get(Office.HAS_HIDDEN_TEXT));
+ assertEquals("true", m.get(Office.HAS_TRACK_CHANGES));
+ assertEquals("true", m.get(Office.HAS_COMMENTS));
+ }
+
+ @Test
+ public void testDotx() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testWORD_template.docx");
+ String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertContains("Metallica", content);
+ assertContains("Hetfield", content);
+ assertContains("one eye open", content);
+ assertContains("Getting the perfect", content);
+ }
+
+ // ---- SAX-specific tests ----
+
@Test
public void testTextDecorationNestedUnderlineStrike() throws Exception {
- // SAX closes u before opening s (since s is outer): <u>unde</u><s><u>r</u></s><u>line</u>
- String xml = getXML("testWORD_various.docx", getParseContext()).xml;
+ String xml = getXML("testWORD_various.docx").xml;
assertContains("<i><u>unde</u><s><u>r</u></s><u>line</u></i>", xml);
}
@Test
public void basicTest() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_2006ml.docx", getParseContext());
+ getRecursiveMetadata("testWORD_2006ml.docx");
assertEquals(8, metadataList.size());
Metadata m = metadataList.get(0);
@@ -146,7 +586,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testPicturesInVariousPlaces() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_embedded_pics.docx", getParseContext());
+ getRecursiveMetadata("testWORD_embedded_pics.docx");
assertEquals(3, metadataList.size());
String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
@@ -170,7 +610,6 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
ParseContext pc = new ParseContext();
OfficeParserConfig officeParserConfig = new OfficeParserConfig();
officeParserConfig.setIncludeDeletedContent(true);
- officeParserConfig.setUseSAXDocxExtractor(true);
officeParserConfig.setIncludeMoveFromContent(true);
pc.set(OfficeParserConfig.class, officeParserConfig);
@@ -187,7 +626,6 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
PasswordProvider passwordProvider = metadata -> "tika";
OfficeParserConfig opc = new OfficeParserConfig();
- opc.setUseSAXDocxExtractor(true);
ParseContext passwordContext = new ParseContext();
passwordContext.set(PasswordProvider.class, passwordProvider);
passwordContext.set(OfficeParserConfig.class, opc);
@@ -198,7 +636,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
for (Map.Entry<String, String> e : tests.entrySet()) {
boolean exc = false;
try {
- getXML(e.getKey(), getParseContext());
+ getXML(e.getKey());
} catch (EncryptedDocumentException ex) {
exc = true;
}
@@ -208,7 +646,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testDOCXParagraphNumbering() throws Exception {
- String xml = getXML("testWORD_numbered_list.docx", getParseContext()).xml;
+ String xml = getXML("testWORD_numbered_list.docx").xml;
assertContains("add a list here", xml);
assertContains("1) This", xml);
assertContains("a) Is", xml);
@@ -240,7 +678,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
"org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor");
List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_macros.docm", getParseContext());
+ getRecursiveMetadata("testWORD_macros.docm");
for (Metadata metadata : metadataList) {
if (metadata.get(Metadata.CONTENT_TYPE).equals("text/x-vbasic")) {
fail("Shouldn't have extracted macros as default");
@@ -251,7 +689,6 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
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);
@@ -280,7 +717,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testEmbedded() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_embeded.docx", getParseContext());
+ getRecursiveMetadata("testWORD_embeded.docx");
Metadata main = metadataList.get(0);
String content = main.get(TikaCoreProperties.TIKA_CONTENT);
assertContains(
@@ -291,9 +728,6 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testInitializationViaConfig() throws Exception {
- //NOTE: this test relies on a bug in the DOM extractor that
- //is passing over the title information.
- //once we fix that, this test will no longer be meaningful!
AutoDetectParser p = (AutoDetectParser) TikaLoader.load(
getConfigPath(OOXMLDocxSAXTest.class, "tika-config-sax-docx.json"))
.loadAutoDetectParser();
@@ -304,7 +738,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testTruncatedSAXDocx() throws Exception {
assertThrows(TikaException.class, () -> {
- getRecursiveMetadata("testWORD_truncated.docx", getParseContext());
+ getRecursiveMetadata("testWORD_truncated.docx");
});
}
@@ -313,12 +747,12 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testHoverAndVmlHyperlinks() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testHoverAndVml.docx", getParseContext());
+ getRecursiveMetadata("testHoverAndVml.docx");
Metadata m = metadataList.get(0);
assertEquals("true", m.get(Office.HAS_HOVER_HYPERLINKS));
assertEquals("true", m.get(Office.HAS_VML_HYPERLINKS));
- String xml = getXML("testHoverAndVml.docx", getParseContext()).xml;
+ String xml = getXML("testHoverAndVml.docx").xml;
assertContains("class=\"external-ref-hlinkHover\"", xml);
assertContains("http://hover.example.com/phishing", xml);
assertContains("class=\"external-ref-vml-shape-href\"", xml);
@@ -328,7 +762,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testMailMerge() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testMailMerge.docx", getParseContext());
+ getRecursiveMetadata("testMailMerge.docx");
Metadata m = metadataList.get(0);
assertEquals("true", m.get(Office.HAS_MAIL_MERGE));
}
@@ -336,11 +770,11 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testAttachedTemplate() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testAttachedTemplate.docx", getParseContext());
+ getRecursiveMetadata("testAttachedTemplate.docx");
Metadata m = metadataList.get(0);
assertEquals("true", m.get(Office.HAS_ATTACHED_TEMPLATE));
- String xml = getXML("testAttachedTemplate.docx", getParseContext()).xml;
+ String xml = getXML("testAttachedTemplate.docx").xml;
assertContains("class=\"external-ref-attachedTemplate\"", xml);
assertContains("example.com/templates", xml);
}
@@ -348,11 +782,11 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testSubdocument() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testSubdocument.docx", getParseContext());
+ getRecursiveMetadata("testSubdocument.docx");
Metadata m = metadataList.get(0);
assertEquals("true", m.get(Office.HAS_SUBDOCUMENTS));
- String xml = getXML("testSubdocument.docx", getParseContext()).xml;
+ String xml = getXML("testSubdocument.docx").xml;
assertContains("class=\"external-ref-subDocument\"", xml);
assertContains("example.org/chapters", xml);
}
@@ -360,16 +794,11 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
@Test
public void testFrameset() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testFrameset.docx", getParseContext());
+ getRecursiveMetadata("testFrameset.docx");
Metadata m = metadataList.get(0);
assertEquals("true", m.get(Office.HAS_FRAMESETS));
}
- /**
- * Test with external DOCX files known to trigger "prefix not bound"
- * from missing namespace declarations in footnote/endnote fragments.
- * Enable by setting system property "tika.test.docx.namespace" to a file path.
- */
@Test
public void testNamespaceInFragments() throws Exception {
String filePath = System.getProperty("tika.test.docx.namespace");
@@ -385,7 +814,7 @@ public class OOXMLDocxSAXTest extends AbstractOOXMLDocxTest {
org.xml.sax.ContentHandler handler =
new org.apache.tika.sax.BodyContentHandler(-1);
try (TikaInputStream tis = TikaInputStream.get(f.toPath())) {
- parser.parse(tis, handler, metadata, getParseContext());
+ parser.parse(tis, handler, metadata, new ParseContext());
}
String[] warnings = metadata.getValues(TikaCoreProperties.TIKA_META_EXCEPTION_WARNING);
for (String w : warnings) {
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/OOXMLPptxDOMTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxDOMTest.java
deleted file mode 100644
index 8b9ca989d9..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxDOMTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.junit.jupiter.api.Test;
-import org.xml.sax.ContentHandler;
-
-import org.apache.tika.config.loader.TikaLoader;
-import org.apache.tika.exception.EncryptedDocumentException;
-import org.apache.tika.io.TikaInputStream;
-import org.apache.tika.metadata.DublinCore;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.Parser;
-import org.apache.tika.parser.PasswordProvider;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
-import org.apache.tika.sax.BodyContentHandler;
-
-/**
- * Runs the shared PPTX tests using the DOM-based parser (default),
- * plus DOM-specific tests.
- */
-public class OOXMLPptxDOMTest extends AbstractOOXMLPptxTest {
-
- @Override
- ParseContext getParseContext() {
- return new ParseContext();
- }
-
- @Test
- public void testVariousPPTXDOMExtra() throws Exception {
- // DOM version has extra assertions for DublinCore.SUBJECT and TikaCoreProperties.SUBJECT
- Metadata metadata = new Metadata();
- getXML("testPPT_various.pptx", metadata, getParseContext());
-
- assertEquals("Subject is here", metadata.get(DublinCore.SUBJECT));
-
- assertContains("Keyword1 Keyword2",
- Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
- assertContains("Subject is here",
- Arrays.asList(metadata.getValues(TikaCoreProperties.SUBJECT)));
- }
-
- @Test
- public void testPowerPointCustomProperties() throws Exception {
- Metadata metadata = new Metadata();
-
- try (TikaInputStream tis =
- getResourceAsStream("/test-documents/testPPT_custom_props.pptx")) {
- ContentHandler handler = new BodyContentHandler(-1);
- ParseContext context = new ParseContext();
- context.set(Locale.class, Locale.US);
- new OOXMLParser().parse(tis, handler, metadata, context);
- }
-
- assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation",
- metadata.get(Metadata.CONTENT_TYPE));
- assertEquals("JOUVIN ETIENNE", metadata.get(TikaCoreProperties.CREATOR));
- assertEquals("EJ04325S", metadata.get(TikaCoreProperties.MODIFIER));
- assertEquals("2011-08-22T13:30:53Z", metadata.get(TikaCoreProperties.CREATED));
- assertEquals("2011-08-22T13:32:49Z", metadata.get(TikaCoreProperties.MODIFIED));
- assertEquals("1", metadata.get(Office.SLIDE_COUNT));
- assertEquals("3", metadata.get(Office.WORD_COUNT));
- assertEquals("Test extraction properties pptx", metadata.get(TikaCoreProperties.TITLE));
- assertEquals("true", metadata.get("custom:myCustomBoolean"));
- assertEquals("3", metadata.get("custom:myCustomNumber"));
- assertEquals("MyStringValue", metadata.get("custom:MyCustomString"));
- assertEquals("2010-12-30T22:00:00Z", metadata.get("custom:MyCustomDate"));
- assertEquals("2010-12-29T22:00:00Z", metadata.get("custom:myCustomSecondDate"));
- }
-
- // TIKA-997:
- @Test
- public void testEmbeddedZipInPPTX() throws Exception {
- String xml = getXML("test_embedded_zip.pptx", getParseContext()).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\" />");
- int k = xml.indexOf("<p>No title</p>");
- assertTrue(h != -1);
- assertTrue(i != -1);
- assertTrue(j != -1);
- assertTrue(k != -1);
- assertTrue(h < i);
- assertTrue(i < j);
- assertTrue(j < k);
- }
-
- // TIKA-1032:
- @Test
- public void testEmbeddedPPTXTwoSlides() throws Exception {
- String xml = getXML("testPPT_embedded_two_slides.pptx", getParseContext()).xml;
- assertContains("<div class=\"embedded\" id=\"slide1_rId7\" />", xml);
- assertContains("<div class=\"embedded\" id=\"slide2_rId7\" />", xml);
- }
-
- @Test
- public void testMacrosInPptm() throws Exception {
-
- //test default is "don't extract macros"
- for (Metadata metadata : getRecursiveMetadata("testPPT_macros.pptm", getParseContext())) {
- if (metadata.get(Metadata.CONTENT_TYPE).equals("text/x-vbasic")) {
- fail("Shouldn't have extracted macros as default");
- }
- }
-
- //now test that they were extracted
- ParseContext context = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setExtractMacros(true);
- context.set(OfficeParserConfig.class, officeParserConfig);
-
- Metadata minExpected = new Metadata();
- minExpected.add(TikaCoreProperties.TIKA_CONTENT.getName(), "Sub Embolden()");
- minExpected.add(TikaCoreProperties.TIKA_CONTENT.getName(), "Sub Italicize()");
- minExpected.add(Metadata.CONTENT_TYPE, "text/x-vbasic");
- minExpected.add(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE,
- TikaCoreProperties.EmbeddedResourceType.MACRO.toString());
-
- assertContainsAtLeast(minExpected,
- getRecursiveMetadata("testPPT_macros.pptm", context));
-
- //test configuring via config file
- Parser parser = TikaLoader.load(
- getConfigPath(OOXMLParserTest.class, "tika-config-dom-macros.json"))
- .loadAutoDetectParser();
- assertContainsAtLeast(minExpected,
- getRecursiveMetadata("testPPT_macros.pptm", parser));
- }
-
- @Test
- public void testEncrypted() throws Exception {
- Map<String, String> tests = new HashMap<>();
- tests.put("testPPT_protected_passtika.pptx",
- "This is an encrypted PowerPoint 2007 slide.");
-
- PasswordProvider passwordProvider = metadata -> "tika";
- ParseContext passwordContext = new ParseContext();
- passwordContext.set(PasswordProvider.class, passwordProvider);
-
- for (Map.Entry<String, String> e : tests.entrySet()) {
- assertContains(e.getValue(), getXML(e.getKey(), passwordContext).xml);
- }
-
- //now try with no password
- for (Map.Entry<String, String> e : tests.entrySet()) {
- boolean exc = false;
- try {
- getXML(e.getKey(), getParseContext());
- } catch (EncryptedDocumentException ex) {
- exc = true;
- }
- assertTrue(exc);
- }
- }
-
- @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 testEmbeddedMediaDOMExtra() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_embeddedMP3.pptx", getParseContext());
- // Verify INTERNAL_PATH is set for embedded media (DOM-specific)
- assertNotNull(metadataList.get(1).get(TikaCoreProperties.INTERNAL_PATH));
- assertTrue(metadataList.get(1).get(TikaCoreProperties.INTERNAL_PATH)
- .contains("/ppt/media/"));
- }
-}
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/OOXMLPptxSAXTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXTest.java
index c9996d0b91..7c3664b98d 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXTest.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXTest.java
@@ -22,13 +22,13 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.xml.sax.ContentHandler;
+import org.apache.tika.TikaTest;
import org.apache.tika.config.loader.TikaLoader;
import org.apache.tika.exception.EncryptedDocumentException;
import org.apache.tika.io.TikaInputStream;
@@ -42,49 +42,294 @@ import org.apache.tika.parser.microsoft.OfficeParserConfig;
import org.apache.tika.sax.BodyContentHandler;
/**
- * Runs the shared PPTX tests using the SAX-based streaming parser,
- * plus SAX-specific tests.
+ * Tests for the PPTX parser.
*/
-public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
+public class OOXMLPptxSAXTest extends TikaTest {
- @Override
- ParseContext getParseContext() {
- ParseContext parseContext = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setUseSAXPptxExtractor(true);
- parseContext.set(OfficeParserConfig.class, officeParserConfig);
- return parseContext;
+ // ---- tests from AbstractOOXMLPptxTest ----
+
+ @Test
+ public void testPowerPoint() throws Exception {
+ String[] extensions = new String[]{"pptx", "pptm", "ppsm", "ppsx", "potm"};
+
+ String[] mimeTypes = new String[]{
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ "application/vnd.ms-powerpoint.presentation.macroenabled.12",
+ "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+ "application/vnd.ms-powerpoint.template.macroenabled.12"};
+
+ for (int i = 0; i < extensions.length; i++) {
+ String extension = extensions[i];
+ String filename = "testPPT." + extension;
+
+ Metadata metadata = new Metadata();
+ ContentHandler handler = new BodyContentHandler();
+
+ try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
+ AUTO_DETECT_PARSER.parse(tis, handler, metadata, new ParseContext());
+
+ assertEquals(mimeTypes[i], metadata.get(Metadata.CONTENT_TYPE),
+ "Mime-type checking for " + filename);
+ assertEquals("Attachment Test", metadata.get(TikaCoreProperties.TITLE));
+ assertEquals("Rajiv", metadata.get(TikaCoreProperties.CREATOR));
+
+ String content = handler.toString();
+ if (extension.equals("thmx")) {
+ assertEquals("", content);
+ } else {
+ assertTrue(content.contains("Attachment Test"),
+ "Text missing for " + filename + "\n" + content);
+ assertTrue(content.contains("This is a test file data with the same content"),
+ "Text missing for " + filename + "\n" + content);
+ assertTrue(content.contains("content parsing"),
+ "Text missing for " + filename + "\n" + content);
+ assertTrue(content.contains("Different words to test against"),
+ "Text missing for " + filename + "\n" + content);
+ assertTrue(content.contains("Mystery"),
+ "Text missing for " + filename + "\n" + content);
+ }
+ }
+ }
}
@Test
- public void basicTest() throws Exception {
+ public void testPowerPointMetadataEarly() throws Exception {
+ String[] extensions = new String[]{"pptx", "pptm", "ppsm", "ppsx", "potm"};
+
+ final String[] mimeTypes = new String[]{
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ "application/vnd.ms-powerpoint.presentation.macroenabled.12",
+ "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+ "application/vnd.ms-powerpoint.template.macroenabled.12"};
+
+ for (int i = 0; i < extensions.length; i++) {
+ String extension = extensions[i];
+ final String filename = "testPPT." + extension;
+ final Metadata metadata = new Metadata();
+
+ final int currentI = i;
+ ContentHandler handler = new BodyContentHandler() {
+ public void startDocument() {
+ assertEquals(mimeTypes[currentI], metadata.get(Metadata.CONTENT_TYPE),
+ "Mime-type checking for " + filename);
+ assertEquals("Attachment Test", metadata.get(TikaCoreProperties.TITLE));
+ assertEquals("Rajiv", metadata.get(TikaCoreProperties.CREATOR));
+ }
+ };
+
+ try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
+ AUTO_DETECT_PARSER.parse(tis, handler, metadata, new ParseContext());
+ }
+ }
+ }
+
+ @Test
+ public void testUnsupportedPowerPoint() throws Exception {
+ String[] extensions = new String[]{"xps", "thmx"};
+ String[] mimeTypes = new String[]{"application/vnd.ms-xpsdocument",
+ "application/vnd.openxmlformats-officedocument"};
+
+ for (int i = 0; i < extensions.length; i++) {
+ String extension = extensions[i];
+ String filename = "testPPT." + extension;
+
+ Metadata metadata = new Metadata();
+ metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, filename);
+ ContentHandler handler = new BodyContentHandler();
+
+ try (TikaInputStream tis = getResourceAsStream("/test-documents/" + filename)) {
+ AUTO_DETECT_PARSER.parse(tis, handler, metadata, new ParseContext());
+ assertEquals(mimeTypes[i], metadata.get(Metadata.CONTENT_TYPE),
+ "Mime-type checking for " + filename);
+ }
+ }
+ }
+
+ @Test
+ public void testVariousPPTX() throws Exception {
+ Metadata metadata = new Metadata();
+ String xml = getXML("testPPT_various.pptx", metadata).xml;
+ assertContains("<p>Footnote appears here", xml);
+ assertContains("<p>[1] This is a footnote.", xml);
+ assertContains("<p>This is the header text.</p>", xml);
+ assertContains("<p>This is the footer text.</p>", xml);
+ assertContains("<p>Here is a text box</p>", xml);
+ assertContains("<p>Bold", xml);
+ assertContains("italic underline superscript subscript", xml);
+ assertContains("<p>Here is a citation:", xml);
+ assertContains("Figure 1 This is a caption for Figure 1", xml);
+ assertContains("(Kramer)", xml);
+ assertContains("<table><tr>\t<td>Row 1 Col 1</td>", xml);
+ assertContains("<td>Row 2 Col 2</td>\t<td>Row 2 Col 3</td></tr>", xml);
+ assertContains("<p>Row 1 column 1</p>", xml);
+ assertContains("<p>Row 2 column 2</p>", xml);
+ assertContains("<p><a href=\"http://tika.apache.org/\">This is a hyperlink</a>", xml);
+ assertContains("<p>Here is a list:", xml);
+ for (int row = 1; row <= 3; row++) {
+ assertContains("<p>Bullet " + row, xml);
+ }
+ assertContains("Here is a numbered list:", xml);
+ for (int row = 1; row <= 3; row++) {
+ assertContains("<p>Number bullet " + row, xml);
+ }
+ for (int row = 1; row <= 2; row++) {
+ for (int col = 1; col <= 3; col++) {
+ assertContains("Row " + row + " Col " + col, xml);
+ }
+ }
+ assertContains("Keyword1 Keyword2", xml);
+ assertEquals("Keyword1 Keyword2", metadata.get(Office.KEYWORDS));
+ assertContains("Subject is here", xml);
+ assertContains("Suddenly some Japanese text:", xml);
+ assertContains("\uff08\uff27\uff28\uff31\uff09", xml);
+ assertContains("\u30be\u30eb\u30b2\u3068\u5c3e\u5d0e\u3001\u6de1\u3005\u3068\u6700\u671f",
+ xml);
+ assertContains("And then some Gothic text:", xml);
+ assertContains("\uD800\uDF32\uD800\uDF3f\uD800\uDF44\uD800\uDF39\uD800\uDF43\uD800\uDF3A",
+ 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);
+ }
+
+ @Test
+ public void testMasterFooter() throws Exception {
+ assertContains("Master footer is here",
+ getXML("testPPT_masterFooter.pptx").xml);
+ }
+
+ @Test
+ @Disabled("can't tell why this isn't working")
+ public void testTurningOffMasterContent() throws Exception {
+ ParseContext context = new ParseContext();
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setIncludeSlideMasterContent(false);
+ context.set(OfficeParserConfig.class, config);
+ String xml = getXML("testPPT_masterFooter.pptx", context).xml;
+ assertNotContained("Master footer", xml);
+ }
+ @Test
+ public void testMasterText() throws Exception {
+ assertContains("Text that I added to the master slide",
+ getXML("testPPT_masterText.pptx").xml);
+
+ ParseContext context = new ParseContext();
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setIncludeSlideMasterContent(false);
+ 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").xml);
+
+ ParseContext context = new ParseContext();
+ OfficeParserConfig config = new OfficeParserConfig();
+ config.setIncludeSlideMasterContent(false);
+ context.set(OfficeParserConfig.class, config);
+ assertNotContained("Text that I added",
+ getXML("testPPT_masterText2.pptx", context).xml);
+ }
+
+ @Test
+ public void testWordArt() throws Exception {
+ assertContains("Here is some red word Art",
+ getXML("testWordArt.pptx").xml);
+ }
+
+ @Test
+ public void testPPTXAutodate() throws Exception {
+ XMLResult result = getXML("testPPT_autodate.pptx");
+ assertContains("<p>Now</p>\n" + "<p>2011-12-19 10:20:04 AM</p>\n", result.xml);
+ }
+
+ @Test
+ public void testPPTXThumbnail() throws Exception {
+ String xml = getXML("testPPTX_Thumbnail.pptx").xml;
+ int a = xml.indexOf(
+ "<body><div class=\"slide-content\"><p>This file contains an embedded thumbnail");
+ int b = xml.indexOf("<div class=\"embedded\" id=\"/docProps/thumbnail.jpeg\" />");
+ assertTrue(a != -1);
+ assertTrue(b != -1);
+ assertTrue(a < b);
+ }
+
+ @Test
+ public void testPPTXDiagramData() throws Exception {
+ assertContains("President",
+ getXML("testPPT_diagramData.pptx").xml);
+ }
+
+ @Test
+ public void testPPTXChartData() throws Exception {
+ String xml = getXML("testPPT_charts.pptx").xml;
+ assertContains("peach", xml);
+ assertContains("March\tApril", xml);
+ assertNotContained("chartSpace", xml);
+ }
+
+ @Test
+ public void testPPTXGroups() throws Exception {
List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_various2.pptx", getParseContext());
+ getRecursiveMetadata("testPPT_groups.pptx");
+ assertEquals(3, metadataList.size());
+ String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertContains("WordArt1", content);
+ assertContains("WordArt2", content);
+ assertContainsCount("Ungrouped text box", content, 1);
+ assertContains("Text box1", content);
+ assertContains("Text box2", content);
+ assertContains("Text box3", content);
+ assertContains("Text box4", content);
+ assertContains("Text box5", content);
+ assertContains("href=\"http://tika.apache.org", content);
+ assertContains("smart1", content);
+ assertContains("MyTitle", content);
+ assertEquals("/image1.jpg",
+ metadataList.get(1).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
+ assertEquals("/thumbnail.jpeg",
+ metadataList.get(2).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
+ }
- assertEquals(15, metadataList.size(), "right number of attachments");
+ @Test
+ public void testEmbeddedMedia() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testPPT_embeddedMP3.pptx");
+ assertEquals(4, metadataList.size());
+ assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ metadataList.get(0).get(Metadata.CONTENT_TYPE));
+ assertEquals("audio/mpeg", metadataList.get(1).get(Metadata.CONTENT_TYPE));
+ assertEquals("image/png", metadataList.get(2).get(Metadata.CONTENT_TYPE));
+ assertEquals("image/jpeg", metadataList.get(3).get(Metadata.CONTENT_TYPE));
+ }
- String mainContent = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ // ---- SAX-specific tests ----
- assertContains("This slide is hidden", mainContent);//TODO: parameterize this
+ @Test
+ public void basicTest() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testPPT_various2.pptx");
- //basic content
- assertContains("FirstBullet", mainContent);
+ assertEquals(15, metadataList.size(), "right number of attachments");
- //hyperlink
+ String mainContent = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertContains("This slide is hidden", mainContent);
+ assertContains("FirstBullet", mainContent);
assertContains("<a href=\"http://tika.apache.org/\">tika_hyperlink</a>", mainContent);
- //hyperlink in cell
assertContains("<a href=\"http://lucene.apache.org/\">lucene_hyperlink</a>",
mainContent);
-
- //text box
assertContains("Slide2TextBox", mainContent);
assertContains("<td>R1c1</td>", mainContent);
-
- //wordArt
assertContains("This is some WordART", mainContent);
-
- //notes
assertContains("NotesForSlide2", mainContent);
assertContains("Notes for slide3", mainContent);
assertContains("NotesMasterHeader", mainContent);
@@ -93,41 +338,27 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
assertContains("NotesWordArt", mainContent);
assertContains("NotesWordArtPage2", mainContent);
assertContains("NotesTableSlide2", mainContent);
-
- //comments
assertContains(
"<p class=\"slide-comment\"><b>Timothy Allison (TA)</b>This is a reply to the " +
"initial comment</p>",
mainContent);
-
- //HandoutMaster
assertContains("HandoutHeader1", mainContent);
assertContains("HandoutFooter", mainContent);
assertContains("HandoutDate", mainContent);
assertContains("TextBoxInHandOut", mainContent);
-
- //text box in master
assertContains("MASTERTEXTBOX", mainContent);
-
- //equation
assertContains("3/4", mainContent);
-
- //make sure footer elements are in their own <p/>
assertContains("<p>12/16/2016</p>", mainContent);
assertContains("<p>8</p>", mainContent);
-
assertContains("<td>NotesTableSlide2", mainContent);
-
assertContains("MASTERFOOTERMSG", mainContent);
-
- //should not include boilerplate from master
assertNotContained("Click to edit Master", mainContent);
assertNotContained("Second level", mainContent);
}
@Test
public void poiBug54916Test() throws Exception {
- String xml = getXML("testPPTX_overlappingRelations.pptx", getParseContext()).xml;
+ String xml = getXML("testPPTX_overlappingRelations.pptx").xml;
assertContains("POI cannot read this", xml);
assertContains("Has a relationship to another slide", xml);
assertContains("can read this too", xml);
@@ -136,14 +367,7 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
@Test
public void testPowerPointCustomProperties() throws Exception {
Metadata metadata = new Metadata();
-
- ParseContext context = new ParseContext();
- context.set(Locale.class, Locale.US);
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setUseSAXPptxExtractor(true);
- context.set(OfficeParserConfig.class, officeParserConfig);
-
- getXML("testPPT_custom_props.pptx", metadata, getParseContext());
+ getXML("testPPT_custom_props.pptx", metadata);
assertEquals("application/vnd.openxmlformats-officedocument.presentationml.presentation",
metadata.get(Metadata.CONTENT_TYPE));
assertEquals("JOUVIN ETIENNE", metadata.get(TikaCoreProperties.CREATOR));
@@ -160,11 +384,10 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
assertEquals("2010-12-29T22:00:00Z", metadata.get("custom:myCustomSecondDate"));
}
- // TIKA-997:
@Test
@Disabled("TODO: add in embedded file markup")
public void testEmbeddedZipInPPTX() throws Exception {
- String xml = getXML("test_embedded_zip.pptx", getParseContext()).xml;
+ String xml = getXML("test_embedded_zip.pptx").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\" />");
@@ -178,39 +401,33 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
assertTrue(j < k);
}
- // TIKA-1032:
@Test
@Disabled("TODO: add in embedded file markup")
public void testEmbeddedPPTXTwoSlides() throws Exception {
- String xml = getXML("testPPT_embedded_two_slides.pptx", getParseContext()).xml;
+ String xml = getXML("testPPT_embedded_two_slides.pptx").xml;
assertContains("<div class=\"embedded\" id=\"slide1_rId7\" />", xml);
assertContains("<div class=\"embedded\" id=\"slide2_rId7\" />", xml);
}
@Test
public void testMacrosInPptm() throws Exception {
-
Metadata parsedBy = new Metadata();
parsedBy.add(TikaCoreProperties.TIKA_PARSED_BY,
"org.apache.tika.parser.microsoft.ooxml.xslf.XSLFEventBasedPowerPointExtractor");
List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_macros.pptm", getParseContext());
+ getRecursiveMetadata("testPPT_macros.pptm");
- //test default is "don't extract macros"
for (Metadata metadata : metadataList) {
if (metadata.get(Metadata.CONTENT_TYPE).equals("text/x-vbasic")) {
fail("Shouldn't have extracted macros as default");
}
}
-
assertContainsAtLeast(parsedBy, metadataList);
- //now test that they are extracted
ParseContext context = new ParseContext();
OfficeParserConfig officeParserConfig = new OfficeParserConfig();
officeParserConfig.setExtractMacros(true);
- officeParserConfig.setUseSAXPptxExtractor(true);
context.set(OfficeParserConfig.class, officeParserConfig);
Metadata minExpected = new Metadata();
@@ -221,11 +438,9 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
TikaCoreProperties.EmbeddedResourceType.MACRO.toString());
metadataList = getRecursiveMetadata("testPPT_macros.pptm", context);
-
assertContainsAtLeast(minExpected, metadataList);
assertContainsAtLeast(parsedBy, metadataList);
- //test configuring via config file
AutoDetectParser parser = (AutoDetectParser) TikaLoader.load(
getConfigPath(OOXMLPptxSAXTest.class, "tika-config-sax-macros.json"))
.loadAutoDetectParser();
@@ -244,9 +459,6 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
PasswordProvider passwordProvider = metadata -> "tika";
ParseContext passwordContext = new ParseContext();
passwordContext.set(PasswordProvider.class, passwordProvider);
- OfficeParserConfig opc = new OfficeParserConfig();
- opc.setUseSAXPptxExtractor(true);
- passwordContext.set(OfficeParserConfig.class, opc);
for (Map.Entry<String, String> e : tests.entrySet()) {
try (TikaInputStream tis = getResourceAsStream("/test-documents/" + e.getKey())) {
@@ -257,7 +469,6 @@ public class OOXMLPptxSAXTest extends AbstractOOXMLPptxTest {
}
ParseContext context = new ParseContext();
- //now try with no password
for (Map.Entry<String, String> e : tests.entrySet()) {
boolean exc = false;
try (TikaInputStream tis = getResourceAsStream("/test-documents/" + e.getKey())) {
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/VSDXParserTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/VSDXParserTest.java
new file mode 100644
index 0000000000..4153293b24
--- /dev/null
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/java/org/apache/tika/parser/microsoft/ooxml/VSDXParserTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.parser.microsoft.ooxml;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.tika.TikaTest;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+
+public class VSDXParserTest extends TikaTest {
+
+ @Test
+ public void testBasicTextExtraction() throws Exception {
+ List<Metadata> metadataList = getRecursiveMetadata("testVISIO.vsdx");
+ String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertEquals("application/vnd.ms-visio.drawing",
+ metadataList.get(0).get(Metadata.CONTENT_TYPE));
+ assertContains("test", content);
+ assertContains("This is a test.", content);
+ assertContains("Nothing fancy.", content);
+ }
+
+ @Test
+ public void testTextExtraction() throws Exception {
+ // POI test file with multiple shapes containing text
+ List<Metadata> metadataList = getRecursiveMetadata("testVISIO_text.vsdx");
+ String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertContains("Text here", content);
+ assertContains("Text there", content);
+ assertContains("Text, text, everywhere!", content);
+ assertContains("Router here", content);
+ }
+
+ @Test
+ public void testRealWorldVSDX() throws Exception {
+ // POI test file 60489 - real-world Visio diagram
+ List<Metadata> metadataList = getRecursiveMetadata("testVISIO_60489.vsdx");
+ String content = metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT);
+ assertContains("HousingConnections.ca", content);
+ assertContains("Content Authors", content);
+ assertContains("Submit Application", content);
+ }
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-docx.json b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-docx.json
index 0a22fa62f4..800a8d621f 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-docx.json
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-docx.json
@@ -1,10 +1,5 @@
{
"parsers": [
- "default-parser",
- {
- "ooxml-parser": {
- "useSAXDocxExtractor": true
- }
- }
+ "default-parser"
]
}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-macros.json b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-macros.json
index e5b644cb7a..86ecdcdb33 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-macros.json
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/configs/tika-config-sax-macros.json
@@ -3,9 +3,7 @@
"default-parser",
{
"ooxml-parser": {
- "extractMacros": true,
- "useSAXDocxExtractor": true,
- "useSAXPptxExtractor": true
+ "extractMacros": true
}
},
{
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_60489.vsdx b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_60489.vsdx
new file mode 100644
index 0000000000..659ecdd585
Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_60489.vsdx differ
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_text.vsdx b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_text.vsdx
new file mode 100644
index 0000000000..39b6401772
Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testVISIO_text.vsdx differ
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLDocxPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLDocxPackageTest.java
deleted file mode 100644
index 26967ab18d..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLDocxPackageTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.tika.TikaTest;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-
-public abstract class AbstractOOXMLDocxPackageTest extends TikaTest {
-
- abstract ParseContext getParseContext();
-
- @Test
- public void testAltFileMHTChunk() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testAltChunkMHT.docx", getParseContext());
- assertEquals(3, metadataList.size());
- assertContains("Example of a table",
- metadataList.get(2).get(TikaCoreProperties.TIKA_CONTENT));
- }
-
- @Test
- public void testAltFileHTMLChunk() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testAltChunkHTML.docx", getParseContext());
- assertEquals(2, metadataList.size());
- assertContains("Example of a table",
- metadataList.get(1).get(TikaCoreProperties.TIKA_CONTENT));
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLPptxPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLPptxPackageTest.java
deleted file mode 100644
index 8b844f1d28..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/AbstractOOXMLPptxPackageTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.tika.TikaTest;
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-
-public abstract class AbstractOOXMLPptxPackageTest extends TikaTest {
-
- abstract ParseContext getParseContext();
-
- @Test
- public void testEmbeddedPDFInPPTX() throws Exception {
- List<Metadata> metadataList =
- getRecursiveMetadata("testPPT_EmbeddedPDF.pptx", getParseContext());
- Metadata pdfMetadata1 = metadataList.get(4);
- assertContains("Apache Tika", pdfMetadata1.get(TikaCoreProperties.TIKA_CONTENT));
- Metadata pdfMetadata2 = metadataList.get(5);
- assertContains("Hello World", pdfMetadata2.get(TikaCoreProperties.TIKA_CONTENT));
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxDOMPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxDOMPackageTest.java
deleted file mode 100644
index 3f6b0f5804..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxDOMPackageTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import org.apache.tika.metadata.Metadata;
-import org.apache.tika.metadata.Office;
-import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.EMFParser;
-
-/**
- * DOM-specific docx package tests.
- */
-public class OOXMLDocxDOMPackageTest extends AbstractOOXMLDocxPackageTest {
-
- @Override
- ParseContext getParseContext() {
- return new ParseContext();
- }
-
- @Test
- public void testEMFAssociatedWithAttachments() throws Exception {
- //TIKA-3968
- List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_EMFAndAttachments.docx", getParseContext());
-
- assertEquals("true", metadataList.get(1).get(EMFParser.EMF_ICON_ONLY));
- assertEquals("true", metadataList.get(3).get(EMFParser.EMF_ICON_ONLY));
- assertEquals("true", metadataList.get(5).get(EMFParser.EMF_ICON_ONLY));
- assertEquals("TestText.txt", metadataList.get(1).get(EMFParser.EMF_ICON_STRING));
- assertEquals("TestPdf.pdf", metadataList.get(3).get(EMFParser.EMF_ICON_STRING));
- assertEquals("testWORD123.docx", metadataList.get(5).get(EMFParser.EMF_ICON_STRING));
-
- assertNull(metadataList.get(2).get(Office.PROG_ID));
- assertEquals("AcroExch.Document.DC", metadataList.get(4).get(Office.PROG_ID));
- assertEquals("Word.Document.12", metadataList.get(6).get(Office.PROG_ID));
-
- assertEquals("TestText.txt",
- metadataList.get(2).get(TikaCoreProperties.RESOURCE_NAME_KEY));
- assertEquals("TestPdf.pdf",
- metadataList.get(4).get(TikaCoreProperties.RESOURCE_NAME_KEY));
- assertEquals("testWORD123.docx",
- metadataList.get(6).get(TikaCoreProperties.RESOURCE_NAME_KEY));
-
- assertEquals("/TestText.txt",
- metadataList.get(2).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
- assertEquals("/TestPdf.pdf",
- metadataList.get(4).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
- assertEquals("/testWORD123.docx",
- metadataList.get(6).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
-
- assertContains("This is Text File",
- metadataList.get(2).get(TikaCoreProperties.TIKA_CONTENT));
- assertContains("This is test PDF document for parser.",
- metadataList.get(4).get(TikaCoreProperties.TIKA_CONTENT));
- assertContains("This is test word document for parser.",
- metadataList.get(6).get(TikaCoreProperties.TIKA_CONTENT));
-
- assertEquals(TikaCoreProperties.EmbeddedResourceType.ATTACHMENT.name(),
- metadataList.get(2).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
- assertEquals(TikaCoreProperties.EmbeddedResourceType.ATTACHMENT.name(),
- metadataList.get(4).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
- assertEquals(TikaCoreProperties.EmbeddedResourceType.ATTACHMENT.name(),
- metadataList.get(6).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
-
- assertEquals(TikaCoreProperties.EmbeddedResourceType.INLINE.name(),
- metadataList.get(1).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
- assertEquals(TikaCoreProperties.EmbeddedResourceType.INLINE.name(),
- metadataList.get(3).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
- assertEquals(TikaCoreProperties.EmbeddedResourceType.INLINE.name(),
- metadataList.get(5).get(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE));
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXPackageTest.java
index 33712f21ba..a08a20572a 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXPackageTest.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLDocxSAXPackageTest.java
@@ -23,32 +23,40 @@ import java.util.List;
import org.junit.jupiter.api.Test;
+import org.apache.tika.TikaTest;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.Office;
import org.apache.tika.metadata.TikaCoreProperties;
-import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.microsoft.EMFParser;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
/**
- * SAX-specific docx package tests.
+ * Docx package tests.
*/
-public class OOXMLDocxSAXPackageTest extends AbstractOOXMLDocxPackageTest {
+public class OOXMLDocxSAXPackageTest extends TikaTest {
- @Override
- ParseContext getParseContext() {
- ParseContext parseContext = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setUseSAXDocxExtractor(true);
- parseContext.set(OfficeParserConfig.class, officeParserConfig);
- return parseContext;
+ @Test
+ public void testAltFileMHTChunk() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testAltChunkMHT.docx");
+ assertEquals(3, metadataList.size());
+ assertContains("Example of a table",
+ metadataList.get(2).get(TikaCoreProperties.TIKA_CONTENT));
+ }
+
+ @Test
+ public void testAltFileHTMLChunk() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testAltChunkHTML.docx");
+ assertEquals(2, metadataList.size());
+ assertContains("Example of a table",
+ metadataList.get(1).get(TikaCoreProperties.TIKA_CONTENT));
}
@Test
public void testEMFAssociatedWithAttachments() throws Exception {
//TIKA-3968
List<Metadata> metadataList =
- getRecursiveMetadata("testWORD_EMFAndAttachments.docx", getParseContext());
+ getRecursiveMetadata("testWORD_EMFAndAttachments.docx");
assertEquals("true", metadataList.get(1).get(EMFParser.EMF_ICON_ONLY));
assertEquals("true", metadataList.get(3).get(EMFParser.EMF_ICON_ONLY));
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxDOMPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxDOMPackageTest.java
deleted file mode 100644
index 007e6c8531..0000000000
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxDOMPackageTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.parser.microsoft.ooxml;
-
-import org.apache.tika.parser.ParseContext;
-
-public class OOXMLPptxDOMPackageTest extends AbstractOOXMLPptxPackageTest {
-
- @Override
- ParseContext getParseContext() {
- return new ParseContext();
- }
-}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXPackageTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXPackageTest.java
index 26b217b19e..f7023ceb52 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXPackageTest.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/microsoft/ooxml/OOXMLPptxSAXPackageTest.java
@@ -16,17 +16,23 @@
*/
package org.apache.tika.parser.microsoft.ooxml;
-import org.apache.tika.parser.ParseContext;
-import org.apache.tika.parser.microsoft.OfficeParserConfig;
+import java.util.List;
-public class OOXMLPptxSAXPackageTest extends AbstractOOXMLPptxPackageTest {
+import org.junit.jupiter.api.Test;
- @Override
- ParseContext getParseContext() {
- ParseContext parseContext = new ParseContext();
- OfficeParserConfig officeParserConfig = new OfficeParserConfig();
- officeParserConfig.setUseSAXPptxExtractor(true);
- parseContext.set(OfficeParserConfig.class, officeParserConfig);
- return parseContext;
+import org.apache.tika.TikaTest;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+
+public class OOXMLPptxSAXPackageTest extends TikaTest {
+
+ @Test
+ public void testEmbeddedPDFInPPTX() throws Exception {
+ List<Metadata> metadataList =
+ getRecursiveMetadata("testPPT_EmbeddedPDF.pptx");
+ Metadata pdfMetadata1 = metadataList.get(4);
+ assertContains("Apache Tika", pdfMetadata1.get(TikaCoreProperties.TIKA_CONTENT));
+ Metadata pdfMetadata2 = metadataList.get(5);
+ assertContains("Hello World", pdfMetadata2.get(TikaCoreProperties.TIKA_CONTENT));
}
}