You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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间接获取。

修改后的代码示例

  1. 调整初始化逻辑,传入父容器的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);
  1. 修改自定义提取器,保存并使用父元数据:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:40:41