2014-11-05 91 views
2

我正在为(不断增长的)非结构化excel文档集合建立自动处理系统。该集合包括旧学校的.xls文件和新的.xlsx文件。在我的基于Java的解决方案中,我已经使用Apache POI工具包来分析文档。如何从excel文件中提取外部引用列表

我还没有解决的一个挑战是如何识别文档之间的链接以便绘制依赖关系。我还没有弄清楚如何方便地提取外部引用列表。对于.xlsx文件我有一个解决方法,将文件解压缩,然后打开包含引用的xml文件。这可以工作,但对于大型文档收集效率不高,也不会为.xls文件提供解决方案。

由于解决方案需要在Linux环境中运行,因此我更喜欢使用不依赖Microsoft Office或关联库的解决方案。

POI能够以某种方式做到这一点吗?如果没有,我会进一步调查哪些图书馆/工具/区域?

+0

'Workbook'对象具有'Connections'类。你需要'OLEDBConnection'的'CommandText'。这会给你链接的工作簿。 – 2014-11-05 13:30:12

+0

请问您是否可以详细阐述建议的解决方案?据我可以从https://poi.apache.org/apidocs/上的文档中看出,“Workbook”接口(也就是实现类“HSSFWorkbook”和“XSSFWorkbook”)授予对底层OLEDB连接的公共访问权限。 – Stern 2014-11-05 14:40:09

+0

您可能必须分支出比Apache-POI更远的分支。你看过LibreOffice吗? LibreOffice有一个API,它可以访问连接。 – 2014-11-05 15:13:30

回答

1

最终,我通过POI源代码工作,并使用反射来获取引用的外部工作簿列表。以下代码已经过测试,可用于POI 3.11版测试版。

对于那些希望在该代码中使用此方法的人的注意事项:因为它处理非公共方法和类,所以它可能会更改,并可能在将来中断。

private LinkedList<String> getWorkbookReferences(HSSFWorkbook wb) { 
    LinkedList<String> references = new LinkedList<>(); 

    try { 
     // 1. Get InternalWorkbook 
     Field internalWorkbookField = HSSFWorkbook.class.getDeclaredField("workbook"); 
     internalWorkbookField.setAccessible(true); 
     InternalWorkbook internalWorkbook = (InternalWorkbook) internalWorkbookField.get(wb); 

     // 2. Get LinkTable (hidden class) 
     Method getLinkTableMethod; 
     getLinkTableMethod = InternalWorkbook.class.getDeclaredMethod("getOrCreateLinkTable", null); 

     getLinkTableMethod.setAccessible(true); 
     Object linkTable = getLinkTableMethod.invoke(internalWorkbook, null); 

     // 3. Get external books method 
     Method externalBooksMethod = linkTable.getClass().getDeclaredMethod("getExternalBookAndSheetName", int.class); 
     externalBooksMethod.setAccessible(true); 

     // 4. Loop over all possible workbooks 
     int i = 0; 
     String[] names; 
     try { 
      while(true) { 
       names = (String[]) externalBooksMethod.invoke(linkTable, i++) ;      if (names != null) { 
        references.add(names[0]); 
       } 
      } 
     } 
     catch (java.lang.reflect.InvocationTargetException e) { 
      if (!(e.getCause() instanceof java.lang.IndexOutOfBoundsException)) { 
       throw e; 
      } 
     } 
    } catch (NoSuchFieldException | NoSuchMethodException | SecurityException | InvocationTargetException | IllegalAccessException e) { 
     e.printStackTrace(); 
    } 

    return references; 
} 
+0

如果您可以在HSSF和XSSF链接表之间找到一些共同点,请在POI Bugzilla中打开一个增强请求,并要求提供一个覆盖这两者的通用接口。这是获得公共类/方法来支持这一点的最佳方式! – Gagravarr 2014-11-06 22:03:48