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