Apache POI 库:如何读取 Word 文档中嵌入的 Excel sheet

Apache POI library : How to read Excel sheet embedded in Word document

我正在使用 Apache POI 库读取 Word 文档并将其转换为 HTML。我有一个包含嵌入式 Excel 作品sheet 的 Word 文档。有没有办法在读取XWPF文档时读取那个嵌入的Excelsheet?

OOXML 包含以下代码:

<w:object w:dxaOrig="6942" w:dyaOrig="3234" w14:anchorId="071813E3">
                <v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
                  <v:stroke joinstyle="miter"/>
                  <v:formulas>
                    <v:f eqn="if lineDrawn pixelLineWidth 0"/>
                    <v:f eqn="sum @0 1 0"/>
                    <v:f eqn="sum 0 0 @1"/>
                    <v:f eqn="prod @2 1 2"/>
                    <v:f eqn="prod @3 21600 pixelWidth"/>
                    <v:f eqn="prod @3 21600 pixelHeight"/>
                    <v:f eqn="sum @0 0 1"/>
                    <v:f eqn="prod @6 1 2"/>
                    <v:f eqn="prod @7 21600 pixelWidth"/>
                    <v:f eqn="sum @8 21600 0"/>
                    <v:f eqn="prod @7 21600 pixelHeight"/>
                    <v:f eqn="sum @10 21600 0"/>
                  </v:formulas>
                  <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
                  <o:lock v:ext="edit" aspectratio="t"/>
                </v:shapetype>
                <v:shape id="_x0000_i1037" type="#_x0000_t75" style="width:347.4pt;height:162pt" o:ole="">
                  <v:imagedata r:id="rId7" o:title=""/>
                </v:shape>
                <o:OLEObject Type="Embed" ProgID="Excel.Sheet.12" ShapeID="_x0000_i1037" DrawAspect="Content" ObjectID="_1653752874" r:id="rId8"/>
              </w:object>

我看到里面嵌入了 OLEObject。但不确定如何阅读其内容。非常感谢任何帮助。

OLEObject 包含在 XWPFRun 中。因此可以检查每个 XWPFRun 是否包含 OLEObject。如果是,则从 OLEObject 中获取 rId 属性。此 ID 链接到 Office Open XML 文档的文档部分。该文档部分后面的包部分的内容类型决定了嵌入的对象类型。因此,根据内容类型,您可以获得 XSSFWorkbookHSSFWorkbook 或其他嵌入的 OLEObject

以下方法演示了这种方法:

...
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.xmlbeans.XmlObject;
...

 void handleOLEObjects(XWPFRun run) {
  CTR ctr = run.getCTR();
  String declareNameSpaces = "declare namespace o='urn:schemas-microsoft-com:office:office'";
  XmlObject[] oleObjects = ctr.selectPath(declareNameSpaces + ".//o:OLEObject");
  for (XmlObject oleObject : oleObjects) {
   XmlObject rIdAttribute = oleObject.selectAttribute("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id");
   if (rIdAttribute != null) {
    String rId = rIdAttribute.newCursor().getTextValue();
    handleOLEObject(run.getDocument(), rId);
   }
  }
 }

 void handleOLEObject(XWPFDocument document, String rId) {
  POIXMLDocumentPart documentPart = document.getRelationById(rId);
  if ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(documentPart.getPackagePart().getContentType())) {
   handleXSSFWorkbook(documentPart.getPackagePart());
  } else if ("application/vnd.ms-excel".equals(documentPart.getPackagePart().getContentType())) {
   handleHSSFWorkbook(documentPart.getPackagePart());
  } //else if ...
 }

 void handleXSSFWorkbook(PackagePart part) {
  try {
   XSSFWorkbook workbook = new XSSFWorkbook(part);
   for (Sheet sheet : workbook) {
    for (Row row : sheet) {
     for (Cell cell : row) {
      System.out.print(cell + "\t");
     }
     System.out.println();
    }
   }
  } catch (Exception ex) {
   ex.printStackTrace();
  }
 }

 void handleHSSFWorkbook(PackagePart part) {
  try {
   HSSFWorkbook workbook = new HSSFWorkbook(part.getInputStream());
   for (Sheet sheet : workbook) {
    for (Row row : sheet) {
     for (Cell cell : row) {
      System.out.print(cell + "\t");
     }
     System.out.println();
    }
   }
  } catch (Exception ex) {
   ex.printStackTrace();
  }
 }

方法 handleOLEObjects 使用 XPathXWPFRun 中获取所有 OLEObject XML 对象。它还获得 rId 属性。如果存在 such,则它调用 handleOLEObject。此方法通过 rIdXWPFDocument 获取链接 POIXMLDocumentPart。然后它根据内容类型确定嵌入了哪种 OLEObjects 并为这些对象调用不同的处理程序方法。