在Tika处理嵌入式文件时如何访问父容器元数据?
问题描述
我正在使用Java版Tika库,通过自定义的EmbeddedDocumentExtractor实现结合RecursiveParserWrapper来处理嵌入式文件,该自定义实现通过重写parseEmbedded方法处理容器内的文件。
我想了解在处理嵌入式文件时,是否能够访问父容器的元数据?或者Tika是否要等所有嵌入式文件处理完成后,才会完成父元数据的处理?
我尝试过在ParseContext中设置RecursiveParserWrapperHandler并传入自定义提取器,代码如下:
TikaConfig config = new TikaConfig(TikaProcessor.class.getResourceAsStream("/tika-config.xml")); AutoDetectParser parser = new AutoDetectParser(config); ParseContext context = new ParseContext(); ContentHandlerFactory factory = new BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.BODY, 100000); RecursiveWrapperParser wrapper = new RecursiveParserWrapper(parser); RecursiveParserWrapperHandler handler = new RecursiveParserWrapperHandler(factory); MyCustomEmbeddedDocumentExtractor myCustomExtractor = new MyCustomEmbeddedDocumentExtractor(context); context.set(RecursiveParserWrapper.class, wrapper); context.set(RecursiveParserWrapperHandler.class, handler); context.set(EmbeddedDocumentExtractor.class, myCustomExtractor); context.set(Parser.class, parser); Metadata metadata = new Metadata(); wrapper.parse(someInputStream, handler, metadata, context);
随后尝试在自定义提取器中访问父元数据:
public class MyCustomEmbeddedDocumentExtractor extends ParsingEmbeddedDocumentExtractor { ParseContext context; public MyCustomEmbeddedDocumentExtractor(ParseContext parentContext) { super(parentContext); this.context = parentContext; } public boolean shouldParseEmbedded(Metadata metadata) { return true; } @Override public void parseEmbedded(InputStream inputStream, ContentHandler contentHandler, Metadata metadata, boolean outputHtml) throws SAXException, IOException { // do some stuff RecursiveParserWrapperHandler wrapperHandler = (RecursiveParserWrapperHandler) context.get(RecursiveParserWrapperHandler.class); if (wrapperHandler != null) { List<Metadata> parentMetadata = wrapperHandler.getMetadataList(); // ==> List has size of zero here? <== } } }
但调用getMetadataList()时,列表初始为空;后续调用parseEmbedded时,该列表才会填充子元数据,说明此方法部分有效,但无法获取父容器元数据。
解决方案
核心原因
Tika的处理流程是先解析父容器的元数据,再处理嵌入式文件,但RecursiveParserWrapperHandler的getMetadataList()是在父容器整个解析流程完成后,才会将父元数据加入列表。因此在处理嵌入式文件的parseEmbedded阶段,父元数据还未被存入列表,导致你看到列表为空。
正确获取父元数据的方式
要在处理嵌入式文件时访问父容器元数据,最直接的方法是在初始化自定义EmbeddedDocumentExtractor时,直接传入父容器的Metadata对象,而非通过RecursiveParserWrapperHandler间接获取。
修改后的代码示例
- 调整初始化逻辑,传入父容器的
Metadata:
// ... 原有初始化代码 ... Metadata parentMetadata = new Metadata(); // 将父容器元数据传入自定义提取器 MyCustomEmbeddedDocumentExtractor myCustomExtractor = new MyCustomEmbeddedDocumentExtractor(context, parentMetadata); context.set(RecursiveParserWrapper.class, wrapper); context.set(RecursiveParserWrapperHandler.class, handler); context.set(EmbeddedDocumentExtractor.class, myCustomExtractor); context.set(Parser.class, parser); wrapper.parse(someInputStream, handler, parentMetadata, context);
- 修改自定义提取器,保存并使用父元数据:
public class MyCustomEmbeddedDocumentExtractor extends ParsingEmbeddedDocumentExtractor { private final ParseContext context; private final Metadata parentMetadata; // 存储父容器元数据 public MyCustomEmbeddedDocumentExtractor(ParseContext parentContext, Metadata parentMetadata) { super(parentContext); this.context = parentContext; this.parentMetadata = parentMetadata; } @Override public boolean shouldParseEmbedded(Metadata metadata) { return true; } @Override public void parseEmbedded(InputStream inputStream, ContentHandler contentHandler, Metadata metadata, boolean outputHtml) throws SAXException, IOException { // 直接访问父容器元数据 String parentDocType = parentMetadata.get(Metadata.CONTENT_TYPE); String parentFileName = parentMetadata.get(Metadata.RESOURCE_NAME_KEY); // 你的嵌入式文件处理逻辑... super.parseEmbedded(inputStream, contentHandler, metadata, outputHtml); } }
补充说明
Metadata是引用类型,若父容器的元数据在解析过程中被更新,自定义提取器中保存的对象会实时反映这些修改。RecursiveParserWrapperHandler的设计定位是收集所有解析完成的文档(父+子)的元数据,仅适合在整个解析流程结束后批量获取,不适合在嵌入式文件处理阶段获取父元数据。
内容的提问来源于stack exchange,提问作者Robert McCoy
相关产品推荐
相关产品推荐

