修改 ODF 和旧 (1997-2003) MS Word 文档的 Apache Tika 解析?
Modify Apache Tika parsing of ODF and old (1997-2003) MS Word docs?
我正在开发一个应用程序,它将对不同格式的大文件进行 Lucene 索引(将它们分成多个 org.apache.lucene.document.Documents)。至少在初始方法中,每个 "Lucene Document" 包含一个 "paragraph".
作为一般规则,Apache Tika 似乎是这方面的天赐之物:您只需向它扔一个文档,它就会吸出所有格式的文本。
但我想详细了解它如何处理更棘手的方面,在我第一次看它如何处理脚注和尾注的过程中,我发现在 .docx 文件中它会给出这个"line",对于有 3 个脚注的行:
|Tecum optime[footnoteRef:2], deinde etiam[footnoteRef:3] cum mediocri amico[footnoteRef:4].
[2: Sed quoniam et advesperascit et mihi ad villam revertendum est, nunc quidem hactenus;
Quod si ita sit, cur opera philosophiae sit danda nescio.] [3: Si quae forte-possumus.
Immo videri fortasse.] [4: Huius ego nunc auctoritatem [sequens idem faciam]. Confecta
res esset. Primum Theophrasti, Strato, physicum se voluit; Ut proverbia non nulla veriora
sint quam vestra dogmata.]|
(注意,为清楚起见,我的代码添加了“|”字符)
... .doc 格式的同一个文件 Tika 给你多个 "lines":
|Tecum optime|
|, deinde etiam|
| cum mediocri amico|
|.|
...
|??|
| ? Sed quoniam et advesperascit et mihi ad villam revertendum est, nunc quidem
hactenus; Quod si ita sit, cur opera philosophiae sit danda nescio. |
|??|
| ? Si quae forte-possumus. Immo videri fortasse. |
|??|
| ? Huius ego nunc auctoritatem [sequens idem faciam]. Confecta res esset. Primum
Theophrasti, Strato, physicum se voluit; Ut proverbia non nulla veriora sint quam
vestra dogmata. |
... 它不仅将原始的 "paragraph" 分成几行,在每个脚注引用处中断,而且还将所有脚注推到处理的末尾。
通过 .docx 文件处理,您可以提取脚注并轻松地将它们 link 到它们所属的句子中。 .doc 处理的方式当然对我的索引目的毫无帮助。事实上,我真的看不出有什么方法可以将最初的 4 "lines" 识别为真正属于同一个 parapraph。
也许可以预料,Tika 对 .doc 等过时格式的处理并不是那么出色。我现在打算看看这里涉及的实际源代码,假设我可以在 Gradle 下载的很多很多源 jar 中找到它,而不是调整代码是否有更多 "conventional" 修改 Tika 对给定格式的解析的方法?我做了一些搜索,但一无所获。
当然,另一种方法可能是将 .doc 文件(和 .odt 文件,见下文)转换为 .docx "on the fly" 以获得更高质量的解析。
PS 解析 LibreOffice .odt 文件(开放文档格式,ODF),一种非过时的格式,同样有问题。 特别是,footnote/endnote-containing 行同样被分成多行。
几天后我的发现供感兴趣的人参考。
首先,Apache 人员似乎并不真的想让你 fiddle 使用 Tika classes。
在尝试调整 MS Word 97-2003 格式(又名 .doc)的处理时,这里涉及的主要 class 是 HWPFDocument
("Horrible Word Processing Format")。 Apache POI 项目的一部分,与 Tika 捆绑在一起。
这个 class 通常会从 .doc 文件中获取 InputStream
并且似乎将文件的不同元素分开而无益,因此脚注等似乎是分开存储的从文本中。 HWPFDocument
是 final
,这只是问题的开始:这里的许多文件依赖于包中或 sub-packages 中的其他 classes,其中许多是 final
或不是 public
(或 protected
)。我得出的结论是,我基本上必须克隆整个 org.apache.poi.hwpf
包,对其进行修改并再次打包。我不会被打扰。
.odt (ODF) 文件类型 最终对我来说真的更重要:non-obsolete 和 non-Micro$oft。这里关键的 class 结果是 org.apache.tika.parser.odf.OpenDocumentContentParser
。这里的问题是它包含一个 private final
内部 class (即他们 真的 不想让你子 class 它甚至使用它的实例出于某种原因!)称为 OpenDocumentElementMappingContentHandler
,它最终实现了 org.xml.sax.ContentHandler
。这里涉及数百个(好吧,很多)ContentHandler
-实施 classes,其中许多 "decorators"。但最终你需要做的是复制这个 class OpenDocumentContentParser
的整个代码,然后把里面的 class 弄乱。我这样做是为了在 startElement
和 endElement
处,根据参数 qName
的值,它切换到或退出可能值 "parse mode" [=64] =] "NOTE_CITATION" or "NODE BODY" ...并且在此模式设置的基础上可以取消调用
super.endElement(namespaceURI, localName, qName);
在 endElement
中。正是这个 super
调用似乎触发了一个字符串的结尾和下一个字符串的开头。要在输出文本中放置脚注编号或正文 beginning/ending 的文本指示,您可以创建 String injectedText
然后转到
super.characters( injectedText.toCharArray(), 0, injectedText.length());
如果合适的话。这是因为实际上 做 的最终 ContentHandler
是 ToTextContentHandler
的一个实例, characters( ... )
其方法只是将 chars
序列添加到 java.io.Writer
实例(是的,我也从未听说过:非常简单)。
希望这对您有所帮助。现在已将我的这个新 class 提交给 Tika 项目,看看他们是否喜欢它的外观。
我正在开发一个应用程序,它将对不同格式的大文件进行 Lucene 索引(将它们分成多个 org.apache.lucene.document.Documents)。至少在初始方法中,每个 "Lucene Document" 包含一个 "paragraph".
作为一般规则,Apache Tika 似乎是这方面的天赐之物:您只需向它扔一个文档,它就会吸出所有格式的文本。
但我想详细了解它如何处理更棘手的方面,在我第一次看它如何处理脚注和尾注的过程中,我发现在 .docx 文件中它会给出这个"line",对于有 3 个脚注的行:
|Tecum optime[footnoteRef:2], deinde etiam[footnoteRef:3] cum mediocri amico[footnoteRef:4].
[2: Sed quoniam et advesperascit et mihi ad villam revertendum est, nunc quidem hactenus;
Quod si ita sit, cur opera philosophiae sit danda nescio.] [3: Si quae forte-possumus.
Immo videri fortasse.] [4: Huius ego nunc auctoritatem [sequens idem faciam]. Confecta
res esset. Primum Theophrasti, Strato, physicum se voluit; Ut proverbia non nulla veriora
sint quam vestra dogmata.]|
(注意,为清楚起见,我的代码添加了“|”字符)
... .doc 格式的同一个文件 Tika 给你多个 "lines":
|Tecum optime|
|, deinde etiam|
| cum mediocri amico|
|.|
...
|??|
| ? Sed quoniam et advesperascit et mihi ad villam revertendum est, nunc quidem
hactenus; Quod si ita sit, cur opera philosophiae sit danda nescio. |
|??|
| ? Si quae forte-possumus. Immo videri fortasse. |
|??|
| ? Huius ego nunc auctoritatem [sequens idem faciam]. Confecta res esset. Primum
Theophrasti, Strato, physicum se voluit; Ut proverbia non nulla veriora sint quam
vestra dogmata. |
... 它不仅将原始的 "paragraph" 分成几行,在每个脚注引用处中断,而且还将所有脚注推到处理的末尾。
通过 .docx 文件处理,您可以提取脚注并轻松地将它们 link 到它们所属的句子中。 .doc 处理的方式当然对我的索引目的毫无帮助。事实上,我真的看不出有什么方法可以将最初的 4 "lines" 识别为真正属于同一个 parapraph。
也许可以预料,Tika 对 .doc 等过时格式的处理并不是那么出色。我现在打算看看这里涉及的实际源代码,假设我可以在 Gradle 下载的很多很多源 jar 中找到它,而不是调整代码是否有更多 "conventional" 修改 Tika 对给定格式的解析的方法?我做了一些搜索,但一无所获。
当然,另一种方法可能是将 .doc 文件(和 .odt 文件,见下文)转换为 .docx "on the fly" 以获得更高质量的解析。
PS 解析 LibreOffice .odt 文件(开放文档格式,ODF),一种非过时的格式,同样有问题。 特别是,footnote/endnote-containing 行同样被分成多行。
几天后我的发现供感兴趣的人参考。
首先,Apache 人员似乎并不真的想让你 fiddle 使用 Tika classes。
在尝试调整 MS Word 97-2003 格式(又名 .doc)的处理时,这里涉及的主要 class 是 HWPFDocument
("Horrible Word Processing Format")。 Apache POI 项目的一部分,与 Tika 捆绑在一起。
这个 class 通常会从 .doc 文件中获取 InputStream
并且似乎将文件的不同元素分开而无益,因此脚注等似乎是分开存储的从文本中。 HWPFDocument
是 final
,这只是问题的开始:这里的许多文件依赖于包中或 sub-packages 中的其他 classes,其中许多是 final
或不是 public
(或 protected
)。我得出的结论是,我基本上必须克隆整个 org.apache.poi.hwpf
包,对其进行修改并再次打包。我不会被打扰。
.odt (ODF) 文件类型 最终对我来说真的更重要:non-obsolete 和 non-Micro$oft。这里关键的 class 结果是 org.apache.tika.parser.odf.OpenDocumentContentParser
。这里的问题是它包含一个 private final
内部 class (即他们 真的 不想让你子 class 它甚至使用它的实例出于某种原因!)称为 OpenDocumentElementMappingContentHandler
,它最终实现了 org.xml.sax.ContentHandler
。这里涉及数百个(好吧,很多)ContentHandler
-实施 classes,其中许多 "decorators"。但最终你需要做的是复制这个 class OpenDocumentContentParser
的整个代码,然后把里面的 class 弄乱。我这样做是为了在 startElement
和 endElement
处,根据参数 qName
的值,它切换到或退出可能值 "parse mode" [=64] =] "NOTE_CITATION" or "NODE BODY" ...并且在此模式设置的基础上可以取消调用
super.endElement(namespaceURI, localName, qName);
在 endElement
中。正是这个 super
调用似乎触发了一个字符串的结尾和下一个字符串的开头。要在输出文本中放置脚注编号或正文 beginning/ending 的文本指示,您可以创建 String injectedText
然后转到
super.characters( injectedText.toCharArray(), 0, injectedText.length());
如果合适的话。这是因为实际上 做 的最终 ContentHandler
是 ToTextContentHandler
的一个实例, characters( ... )
其方法只是将 chars
序列添加到 java.io.Writer
实例(是的,我也从未听说过:非常简单)。
希望这对您有所帮助。现在已将我的这个新 class 提交给 Tika 项目,看看他们是否喜欢它的外观。