我正在寻找一种用于解析PDF和MS Office文档格式的分析器,以从文件中提取表格信息。当我看到Apache Tika时,我正在考虑编写单独的实现。我能够从这些文件格式中提取完整的文本。但我的要求是提取表格数据,其中我期望以键值格式呈现2列。我检查了网络上大多数可用的解决方案,但没有找到任何可以解决问题的提示。
我正在寻找一种用于解析PDF和MS Office文档格式的分析器,以从文件中提取表格信息。当我看到Apache Tika时,我正在考虑编写单独的实现。我能够从这些文件格式中提取完整的文本。但我的要求是提取表格数据,其中我期望以键值格式呈现2列。我检查了网络上大多数可用的解决方案,但没有找到任何可以解决问题的提示。
我已经使用Apache POI分别实现了MS格式的内容,然后回到Tika处理PDF。Tika处理文档的方式是将其输出为"SAX基于XHTML事件"1。
因此,我们可以编写自定义SAX实现来解析文件。
结构化文本输出的形式为(避免元数据):
<body><div class="page"><p/>
<p>Key1 Value1 </p>
<p>Key2 Value2 </p>
<p>Key3 Value3</p>
<p/>
</div>
</body>
<p>
标签,这意味着我们失去了结构。直到目前版本1.14都是这种情况。未来可能会解决这个问题,但目前没有计划朝这个方向努力。InputStream is = part.getInputStream(); // input-stream of PDF or PDF part
// Aspose add pipes ("|")
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Document pdfDocument = new Document(is); // load existing PDF file
PageCollection pageCollection = pdfDocument.getPages();
int iNumPages = pageCollection.size();
for(int i = 1; i <= iNumPages; i++)
{
Page page = pageCollection.get_Item(i);
TableAbsorber absorber = new TableAbsorber();// Create TableAbsorber object to find tables
absorber.visit(page);// Visit first page with absorber
IGenericList<AbsorbedTable> listTables = absorber.getTableList();
for(AbsorbedTable absorbedTable : listTables)
{
IGenericList<AbsorbedRow> listRows = absorbedTable.getRowList();
for(AbsorbedRow absorbedRow : listRows)
{
IGenericList<AbsorbedCell> listCells = absorbedRow.getCellList();
for(AbsorbedCell absorbedCell : listCells)
{
TextFragmentCollection collectionTextFrag = absorbedCell.getTextFragments();
Rectangle rectangle = absorbedCell.getRectangle();
// Add pipes ("|") to indicate table ends
TextBuilder textBuilder = new TextBuilder(page);
TextFragment textFragment = new TextFragment("|");
double x = rectangle.getURX();
double y = rectangle.getURY();
textFragment.setPosition(new Position(x, y));
textBuilder.appendText(textFragment);
}
}
}
}
pdfDocument.save(outputStream);
is = new ByteArrayInputStream(outputStream.toByteArray()); // input-steam of modified PDF with pipes included ("|")
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
PDFParser pdfParser = new PDFParser();
PDFParserConfig config = pdfParser.getPDFParserConfig();
config.setSortByPosition(true); // needed for text in correct order
pdfParser.setPDFParserConfig(config);
//InputStream stream = new ByteArrayInputStream(sIS.getBytes(StandardCharsets.UTF_8));
pdfParser.parse(is, handler, metadata, context);
String sPdfData = handler.toString();
我在这里找到了一篇非常有用的博客文章,它使用ContentHandlerDecorator
(使用Groovy,但足够相似)解析表格:
https://opensource.com/article/17/8/tika-groovy
我将其改编为仅将所有<td>
部分解析为制表符分隔行,并通过跟随<tr>
标记将行收集到列表中,因为我需要表格行保持完整,但不需要表格单元格内的特殊逻辑。
您可以将您的装饰器传递给BodyHandler,它将其包装为委托,如下所示:
new AutoDetectParser().parse(inputStream,
new BodyContentHandler(new MyContentHandlerDecorator()),
new Metadata());