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 2023/04/11 18:47:13 UTC

[tika] branch main updated: TIKA-4013 (#1071)

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 dd1ee0732 TIKA-4013 (#1071)
dd1ee0732 is described below

commit dd1ee0732e92cb979e2f0882cb0bdf070ed508cb
Author: Tim Allison <ta...@apache.org>
AuthorDate: Tue Apr 11 14:47:06 2023 -0400

    TIKA-4013 (#1071)
    
    * TIKA-4013 -- add extraction of rendition layout and version from epub
---
 CHANGES.txt                                        |  2 +
 .../main/java/org/apache/tika/metadata/Epub.java   | 36 ++++++++
 .../org/apache/tika/parser/epub/EpubParser.java    |  6 +-
 .../org/apache/tika/parser/epub/OPFParser.java     | 96 ++++++++++++++++++++++
 .../apache/tika/parser/epub/EpubParserTest.java    | 19 ++++-
 5 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index bcdea6c7a..36c880824 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -6,6 +6,8 @@ Release 2.7.1 - ???
 
    * Add detection and a parser for ActiveMime files (TIKA-3987).
 
+   * Add extraction of rendition layout value and version from Epub (TIKA-4013).
+
    * Users may now avoid the ZeroByteFileException via a
      setting on the AutoDetectParserConfig (TIKA-3976).
 
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Epub.java b/tika-core/src/main/java/org/apache/tika/metadata/Epub.java
new file mode 100644
index 000000000..c6e3c3c33
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Epub.java
@@ -0,0 +1,36 @@
+/*
+ * 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.metadata;
+
+/**
+ * EPub properties collection.
+ *
+ * @since Apache Tika 2.8.0
+ */
+public interface Epub {
+
+    String EPUB_PREFIX = "epub" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER;
+
+    /**
+     * This is set to &quot;pre-paginated&quot; if any itemref on the spine or the
+     * metadata has a &quot;pre-paginated&quot; value, &quot;reflowable&quot; otherwise.
+     */
+    Property RENDITION_LAYOUT = Property.externalClosedChoise(EPUB_PREFIX + "rendition:layout",
+            "pre-paginated", "reflowable");
+
+    Property VERSION = Property.externalText(EPUB_PREFIX + "version");
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/EpubParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/EpubParser.java
index 816030e37..75e5eaf69 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/EpubParser.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/EpubParser.java
@@ -81,6 +81,8 @@ public class EpubParser extends AbstractParser {
     @Field
     boolean streaming = false;
     private Parser meta = new DcXMLParser();
+
+    private Parser opf = new OPFParser();
     private Parser content = new EpubContentParser();
 
     public Parser getMetaParser() {
@@ -143,7 +145,7 @@ public class EpubParser extends AbstractParser {
             } else if (entry.getName().equals("metadata.xml")) {
                 meta.parse(zip, new DefaultHandler(), metadata, context);
             } else if (entry.getName().endsWith(".opf")) {
-                meta.parse(zip, new DefaultHandler(), metadata, context);
+                opf.parse(zip, new DefaultHandler(), metadata, context);
             } else if (entry.getName().endsWith(".htm") || entry.getName().endsWith(".html") ||
                     entry.getName().endsWith(".xhtml") || entry.getName().endsWith(".xml")) {
                 content.parse(zip, bodyHandler, metadata, context);
@@ -230,7 +232,7 @@ public class EpubParser extends AbstractParser {
         if (zae == null || !zipFile.canReadEntryData(zae)) {
             return false;
         }
-        meta.parse(zipFile.getInputStream(zae), new DefaultHandler(), metadata, context);
+        opf.parse(zipFile.getInputStream(zae), new DefaultHandler(), metadata, context);
 
         ContentOrderScraper contentOrderScraper = new ContentOrderScraper();
         try (InputStream is = zipFile.getInputStream(zae)) {
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/OPFParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/OPFParser.java
new file mode 100644
index 000000000..129c63800
--- /dev/null
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/epub/OPFParser.java
@@ -0,0 +1,96 @@
+/*
+ * 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.epub;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.tika.metadata.Epub;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.parser.xml.DcXMLParser;
+import org.apache.tika.sax.TeeContentHandler;
+import org.apache.tika.utils.StringUtils;
+import org.apache.tika.utils.XMLReaderUtils;
+
+/**
+ * Use this to parse the .opf files
+ */
+public class OPFParser extends DcXMLParser {
+
+    @Override
+    protected ContentHandler getContentHandler(ContentHandler handler, Metadata metadata,
+                                               ParseContext context) {
+        //set default.  This will be overwritten if it is pre-paginated
+        metadata.set(Epub.RENDITION_LAYOUT, "reflowable");
+        return new TeeContentHandler(super.getContentHandler(handler, metadata, context),
+                new OPFHandler(metadata));
+    }
+
+    private class OPFHandler extends DefaultHandler {
+        private final Metadata metadata;
+        boolean inRenditionLayout = false;
+        StringBuilder sb = new StringBuilder();
+
+        public OPFHandler(Metadata metadata) {
+            this.metadata = metadata;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attributes)
+                throws SAXException {
+            //check each item on spine for pre-paginated
+            if ("itemref".equals(localName)) {
+                String val = XMLReaderUtils.getAttrValue("properties", attributes);
+                if (val != null && val.contains("rendition:layout-pre-paginated")) {
+                    metadata.set(Epub.RENDITION_LAYOUT, "pre-paginated");
+                }
+            } else if ("meta".equals(localName)) {
+                String prop = XMLReaderUtils.getAttrValue("property", attributes);
+                if ("rendition:layout".equals(prop)) {
+                    inRenditionLayout = true;
+                }
+            } else if ("package".equals(localName)) {
+                String v = XMLReaderUtils.getAttrValue("version", attributes);
+                if (!StringUtils.isBlank(v)) {
+                    metadata.set(Epub.VERSION, v);
+                }
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            if (inRenditionLayout && "meta".equals(localName)) {
+                String layout = sb.toString();
+                if ("pre-paginated".equals(layout)) {
+                    metadata.set(Epub.RENDITION_LAYOUT, "pre-paginated");
+                }
+                inRenditionLayout = false;
+                sb.setLength(0);
+            }
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) throws SAXException {
+            if (inRenditionLayout) {
+                sb.append(ch, start, length);
+            }
+        }
+    }
+}
diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/epub/EpubParserTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/epub/EpubParserTest.java
index 805417fbc..57e6a9a3b 100644
--- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/epub/EpubParserTest.java
+++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/epub/EpubParserTest.java
@@ -22,10 +22,12 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import java.io.InputStream;
 import java.util.List;
 
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import org.apache.tika.TikaTest;
 import org.apache.tika.config.TikaConfig;
+import org.apache.tika.metadata.Epub;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.parser.AutoDetectParser;
@@ -37,7 +39,7 @@ public class EpubParserTest extends TikaTest {
     public void testXMLParser() throws Exception {
 
         XMLResult xmlResult = getXML("testEPUB.epub");
-
+        assertEquals("2.0", xmlResult.metadata.get(Epub.VERSION));
         assertEquals("application/epub+zip", xmlResult.metadata.get(Metadata.CONTENT_TYPE));
         assertEquals("en", xmlResult.metadata.get(TikaCoreProperties.LANGUAGE));
         assertEquals("This is an ePub test publication for Tika.",
@@ -65,6 +67,7 @@ public class EpubParserTest extends TikaTest {
     @Test
     public void testEpubOrder() throws Exception {
         List<Metadata> metadataList = getRecursiveMetadata("testEPUB.epub");
+        assertEquals("2.0", metadataList.get(0).get(Epub.VERSION));
 
         //test attachments
         assertEquals(2, metadataList.size());
@@ -111,7 +114,21 @@ public class EpubParserTest extends TikaTest {
         //TIKA-2310
         List<Metadata> metadataList = getRecursiveMetadata("testEPUB_xml_ext.epub");
         assertEquals(1, metadataList.size());
+        assertEquals("2.0", metadataList.get(0).get(Epub.VERSION));
         assertContains("It was a bright cold day in April",
                 metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT));
     }
+
+    @Test
+    @Disabled("add files to repo?")
+    public void testPrePaginated() throws Exception {
+        //this file has pre-paginated on an itemRef in a spine
+        //https://github.com/IDPF/epub3-samples/releases/download/20170606/cole-voyage-of-life.epub
+
+        //this file has pre-paginated in header metadata
+        //https://github.com/IDPF/epub3-samples/releases/download/20170606/cole-voyage-of-life-tol.epub
+
+        List<Metadata> metadataList = getRecursiveMetadata("cole-voyage-of-life.epub");
+        assertEquals("pre-paginated", metadataList.get(0).get(Epub.RENDITION_LAYOUT));
+    }
 }