我正在寻找pdf和MS office文档格式的解析器,以从文件中提取表格信息。当我看到Apache Tika时,正在考虑编写单独的实现。我可以从任何这些文件格式中提取全文。但我的要求是提取表格数据,我希望在键值格式中有2列。我检查了网络中可用的大部分内容,但找不到任何解决方案。 有什么指针吗?
答案 0 :(得分:4)
我继续使用apache poi为MS格式单独实现它。我回到Tika获取PDF格式。 Tika对文档的看法是将其输出为“基于SAX的XHTML事件”1
基本上我们可以编写一个自定义SAX实现来解析文件。
结构文本输出的格式为(避免使用Meta细节)
<body><div class="page"><p/>
<p>Key1 Value1 </p>
<p>Key2 Value2 </p>
<p>Key3 Value3</p>
<p/>
</div>
</body>
在我们的SAX实现中,我们可以将第一部分视为关键(对于我的问题,我已经知道了密钥,我正在寻找值,因此它是一个子字符串)。
使用逻辑
覆盖public void characters(char [] ch,int start,int length)请注意,对于我的情况,内容的结构是固定的,我知道正在进入的键,所以很容易这样做。这不是通用的解决方案
答案 1 :(得分:3)
Tika不解析表格信息。实际上令人困惑的部分是它将表格标签转换为<p>
,这实际上意味着我们失去了结构。直到当前版本1.14为止。在未来可能会得到补救,但到目前为止还没有计划朝这个方向努力。
你可以参考JIRA讨论Tika中的这个缺点。 在JIRA之后,wiki也被更新以反映这种不足。[免责声明:我提出了JIRA]
现在解决方案部分:根据我的经验,Aspose.Pdf for Java在将pdf转换为html方面做得非常出色。但它的许可。您可以通过免费试用版查看质量。 Code and example links
答案 2 :(得分:0)
我使用了tika(tika-app-1.19.jar)和aspose(aspose-pdf-18.9.1.jar)的组合...
我首先使用Aspose修改pdf,在表列的末尾添加管道('|')... ...然后将其读入Tika并将其转换为文本...
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 ("|")
现在上面的pdf输入流在表单元格末尾带有管道(“ |”)可以拉到Tika中并更改为文本...
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();
答案 3 :(得分:0)
我在这里找到了一篇非常有用的博客文章,该文章使用ContentHandlerDecorator
解析表(使用Groovy,但足够类似;):
https://opensource.com/article/17/8/tika-groovy
我将其修改为仅将所有<td>
部分解析成一个制表符分隔的行,并通过跟随<tr>
标签来收集列表中的行,因为我需要表行保持完整但没有特殊之处表格单元格内部的逻辑。
您可以将Decorator传递给BodyHandler,将其包装为委托,如下所示:
new AutoDetectParser().parse(inputStream,
new BodyContentHandler(new MyContentHandlerDecorator()),
new Metadata());