如何使用Apache POI从Excel电子表格中获取图表信息?

问题描述 投票:4回答:4

是否可以使用Apache POI从Office 2007 (xlsx OpenXML)电子表格中提取图表信息?我已经设法读取了电子表格,甚至得到了指向图表的部分,但不确定如何从这部分中获取任何信息,例如图表类型、图表数据等。

XSSFWorkbook xwb = new XSSFWorkbook("charts_lines.xlsx");

XSSFSheet sheet = xwb.getSheetAt(0);

我也可以通过迭代包的部分来检索图表部分,但我不知道如何继续检索关于图表的任何信息?

注意,我对使用POI创建图表不感兴趣,只是尽可能多的读取图表信息......我也没有保存一个xlsx。我只是想提取线的颜色、标签、数据、图表类型(饼状、线状、条状等)。

apache excel charts openxml apache-poi
4个回答
6
投票

目前还没有高级别的表示方法,所以你需要下放到xmlbeans级别,并使用低级别的CT*对象。

对于图表表,有 XSSFChartSheet 这将给你一个CTChartsheet对象,它有一点信息。

对于这两个 XSSFChartXSSFChartSheet (常规和图表表),你需要通过图纸来获取图表。每个有图表的工作表都应该有一个Drawing,而图表是从Drawing中获得链接的,而不是工作表本身。

从r1090442开始(所以POI 3.8或更新),在XSSFDrawing上有一个方法可以给你所有的XSSFChart对象(是chartschart#.xml部分的封装器)。如果你是在一个非常非常老的POI版本上,使用CTDrawing来获取图表的细节,抓取对应的chartschart#.xml部分,然后让xmlbeans给你它的CT对象。无论哪种方式都能让你得到标题、类型、数据范围等。

虽然这有点麻烦,所以如果你能找到一些好的CTChart对象,请考虑给POI发送一个补丁!你可以使用XML来读取图表数据。


5
投票

你可以使用以下方法读取XML图表数据 XSSFDrawing

喜欢

 XSSFDrawing drawing = ((XSSFSheet)sheet).createDrawingPatriarch();
        System.out.println(drawing.getCTDrawing().toString());

将整个图表打印成 XMl 并使用

drawing.getCharts();

你可以在其中添加Iterator来浏览图表。


2
投票

我不知道你的问题的确切答案,但是OpenXML SDK 2.0自带了一个 DocumentReflector.exe 工具,它将向您展示图表是如何定义的(包括SpreadsheetML和DrawingML包之间的所有关系)。关于这个工具的更多信息,请参见 本文.


0
投票

是的,它可以通过以下方式读取任何类型的图表 Apache POI. 但是在读取任何图表信息之前,你需要知道你所接收的XML字符串,因为这可能是基于不同的图表类型,即饼状图、线状图、条状图、散点图或混合图(两个或多个图表的组合)等。因此,对于不同类型的图表,你的方法会有所不同。

对于一个简单的条形图,比如这样。

enter image description here

你的XML将看起来像这样。

<xml-fragment ...>
  <c:title>
    <c:tx>
      <c:rich>
        ...
        <a:p>
          ...
          <a:r>
            ...
            <a:t>Employee Salary</a:t>
          </a:r>
        </a:p>
      </c:rich>
    </c:tx>
    ...
  </c:title>
  ...
  <c:plotArea>
    ...
    <c:barChart>
      ...
      <c:ser>
        ...
        <c:cat>
          <c:strRef>
            ...
            <c:strCache>
              <c:ptCount val="5"/>
              <c:pt idx="0">
                <c:v>Tom</c:v>
              </c:pt>
              <c:pt idx="1">
                <c:v>John</c:v>
              </c:pt>
              <c:pt idx="2">
                <c:v>Harry</c:v>
              </c:pt>
              <c:pt idx="3">
                <c:v>Sam</c:v>
              </c:pt>
              <c:pt idx="4">
                <c:v>Richa</c:v>
              </c:pt>
            </c:strCache>
          </c:strRef>
        </c:cat>
        <c:val>
          <c:numRef>
            ...
            <c:numCache>
              <c:formatCode>"$"#,##0</c:formatCode>
              <c:ptCount val="5"/>
              <c:pt idx="0">
                <c:v>1000</c:v>
              </c:pt>
              <c:pt idx="1">
                <c:v>700</c:v>
              </c:pt>
              <c:pt idx="2">
                <c:v>300</c:v>
              </c:pt>
              <c:pt idx="3">
                <c:v>900</c:v>
              </c:pt>
              <c:pt idx="4">
                <c:v>800</c:v>
              </c:pt>
            </c:numCache>
          </c:numRef>
        </c:val>
        ...
      </c:ser>
      ...
    </c:barChart>
    ...
  </c:plotArea>
  ...
</xml-fragment>

现在基于上面的XML字符串,我们可以使用CT*类和它的各种方法来使用Apache POI遍历整个XML。让我们看看如何读取 图表标题, 标签(员工姓名)系列(雇员薪金) 使用POI。

Workbook workbook = new XSSFWorkbook(new File(PATH));
Sheet sheet = workbook.getSheet("GraphSheet");

XSSFSheet xsheet = (XSSFSheet) sheet;
XSSFDrawing drawing = xsheet.getDrawingPatriarch();
if (drawing != null) {
    List<XSSFChart> charts = drawing.getCharts();

    for (int chartIndex = 0; charts != null && chartIndex < (charts.size()); chartIndex++) {

        XSSFChart chart = charts.get(chartIndex);

        CTChart chart2 = chart.getCTChart();
        CTPlotArea plot = chart2.getPlotArea();
        System.out.println("Chart Title :" + chart2.getTitle().getTx().getRich().getPArray(0).getRArray(0).getT());

        CTBarSer[] ctScaSerList = plot.getBarChartArray(0).getSerArray();

        for (CTBarSer ctLineSer : ctScaSerList) {

            CTStrVal[] ctStrVals = ctLineSer.getCat().getStrRef().getStrCache().getPtArray();
            for (int i = 0; i < ctStrVals.length; i++) {
                System.out.print(ctStrVals[i].getV() + ",");
            }
            System.out.println();
            CTNumVal[] ctXNumVal = ctLineSer.getVal().getNumRef().getNumCache().getPtArray();

            for (int i = 0; i < ctXNumVal.length; i++) {
                System.out.print(ctXNumVal[i].getV() + ",");
            }

        }
    }
}

Console:

Chart Title :Employee Salary
Tom,John,Harry,Sam,Richa,
1000,700,300,900,800,

注:这里,我们的想法是 首先读取XML字符串(因为可能根据你的图形类型而不同)和 然后据此遍历整个XML.

© www.soinside.com 2019 - 2024. All rights reserved.