使用POI库时,图表的顺序与预期不同

问题描述 投票:0回答:1

我尝试使用 POI 库仅修改预定义图表格式的数据。

最多三个图表的顺序是准确的,但除此之外,检索它们的顺序不正确。有办法处理吗?

下面是示例代码。你能帮忙吗?

    XWPFDocument document = new XWPFDocument(new FileInputStream(templateFile));

    System.out.println(document.getCharts().get(0));
    System.out.println(document.getCharts().get(1))
    System.out.println(document.getCharts().get(2));
    System.out.println(document.getCharts().get(3));

名称:/word/charts/chart4.xml - 内容类型:application/vnd.openxmlformats-officedocument.drawingml.chart+xml 名称:/word/charts/chart5.xml - 内容类型:application/vnd.openxmlformats-officedocument.drawingml.chart+xml 名称:/word/charts/chart1.xml - 内容类型:application/vnd.openxmlformats-officedocument.drawingml.chart+xml 名称:/word/charts/chart2.xml - 内容类型:application/vnd.openxmlformats-officedocument.drawingml.chart+xml

enter image description here

ms-word apache-poi
1个回答
0
投票

通过XWPFDocument.getCharts获取的图表顺序就是

/word/_rels/document.xml.rels
中保存的文档到图表关系的顺序。该顺序与文档正文中图表的出现顺序相对应是不可靠的。请参阅https://svn.apache.org/viewvc/poi/tags/REL_5_2_3/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java?view=markup#l237 .

要按照文档正文中出现的顺序获取图表,它们必须是 Apache POI 的正文元素。不幸的是他们不是。 Microsoft Word 文档中还有许多其他元素 Apache POI 不将其视为正文元素。

您可以等到 Apache POI 扩展其代码来考虑所有可能的正文元素。但这可能会很长一段时间。

或者您可能知道所有 Office Open XML 文件(

*.docx
*.xlsx
*.pptx
...)只是包含 XML 文件的 ZIP 存档。因此,人们可以简单地解压缩一个
*.docx
文件并查看它。在
/word/document.xml
中,您可以找到所有主体元素的 XML。在那里您将看到图表位于文本运行元素中包含的绘图元素中。图表元素通过关系 id 链接到
/word/charts/
中的真实图表。因此,如果知道如何使用 Java 处理 XML,那么就可以按照文本运行的顺序获取绘图,然后通过关系 id 从绘图中获取图表。

完整示例:

import java.io.FileInputStream;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;

import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.SimpleValue;
import org.apache.xmlbeans.XmlCursor;

import java.util.List;
import java.util.ArrayList;

public class WordGetAllChartDrawingsFromRuns {

 private static List<CTDrawing> getAllDrawings(XWPFRun run) throws Exception {
  CTR ctR = run.getCTR();
  XmlCursor cursor = ctR.newCursor();
  cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:drawing");
  List<CTDrawing> drawings = new ArrayList<CTDrawing>();
  while (cursor.hasNextSelection()) {
   cursor.toNextSelection();
   XmlObject obj = cursor.getObject();
   CTDrawing drawing = CTDrawing.Factory.parse(obj.newInputStream());
   drawings.add(drawing);
  }
  return drawings;
 }

 private static XWPFChart getChartFromDrawing(XWPFDocument document, CTDrawing drawing) throws Exception {
  XWPFChart result = null;
  XmlCursor cursor = drawing.newCursor();
  cursor.selectPath("declare namespace c='http://schemas.openxmlformats.org/drawingml/2006/chart' declare namespace r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' .//c:chart/@r:id");
  while (cursor.hasNextSelection()) {
   cursor.toNextSelection();
   XmlObject obj = cursor.getObject();
   String rId = ((SimpleValue)obj).getStringValue();
   result = (XWPFChart)document.getRelationById(rId);
  }
  return result;
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument(new FileInputStream("./WordDocumentContainingCharts.docx"));

  for (IBodyElement bodyElement : document.getBodyElements()) {
   if (bodyElement instanceof XWPFParagraph) {
    XWPFParagraph paragraph = (XWPFParagraph) bodyElement;
    for(IRunElement runElement : paragraph.getIRuns()) {
     if (runElement instanceof XWPFRun) {
      XWPFRun run = (XWPFRun) runElement;
      List<CTDrawing> drawings = getAllDrawings(run);
      for (CTDrawing drawing : drawings) {
       XWPFChart chart = getChartFromDrawing(document, drawing);
       System.out.println(chart);
      }
     }
    }
   }
  }

  document.close();
 }
}

免责声明:这段代码,就像我这里的所有代码示例一样,是一个展示原理的最小示例。它应该可以工作,但仅通过复制/粘贴即可在生产性用例中使用还很遥远。人们需要理解代码才能将其实现为高效可用的代码。

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