我们正在尝试使用Apache POI 3.16从PowerPoint幻灯片中删除图表,但我们遇到了困难。
我们的代码执行以下步骤:
这很好。
在某些时候,我们需要从给定的幻灯片中删除图表。这是我们的尝试:
OPCPackage pkg = ppt.getPackage();
String chartRelationId = slide.getRelationId(chart);
pkg.removeRelationship(chartRelationId);
pkg.removePart(chart.getPackagePart());
< code>pkg.removePart()调用似乎可以工作,但是将最终的PowerPoint文档写入磁盘失败,并出现一个异常,指出无法删除部件文件(可能是因为我们已经删除了它)。
<code>包。removeRelationship()调用也会在将文档写入磁盘时触发一个异常,该异常表明核心。xml
已存在。
是否可以使用Apache POI从PowerPoint幻灯片中删除图表?如果是,如何?
由于<code>XSLFChart</code>处于@Beta状态,因此直到现在还没有明确的<code>Shape</code>图表。因此,使用<code>apache poi</code>,我们只能得到包含图表的<code>XSLFGraphicFrame</code>。但从幻灯片中删除<code>XSLFGraphicFrame</code>并不会同时删除所有相关的图表部分。因此,自上而下移除相关图表部分意味着直到现在才实现从<code>POIXLDocumentPart</code>级别向下到<code>PackagePart</code>级别。由于<code>POIXLDocumentPart</code>中的所有相关方法都受到保护,并且<code>XSLFChart</code>本身是最终的,因此不太容易解决。
下面的代码显示了问题。评论如下。
该代码从第一张幻灯片中删除所有图表,并删除所有关系和相关部分,这些部分将是:/ppt/嵌入/Microsoft_Excel_WorksheetN.xlsx
,/ppt/图表/颜色N.xml
和/ppt/图表/样式N.xml
。只有 /ppt/图表/图表N.xml
不能被删除,因为它是注释。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.xmlbeans.XmlObject;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Pattern;
public class ReadPPTRemoveChart {
public static void main(String[] args) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("PPTWithCharts.pptx"));
XSLFSlide slide = slideShow.getSlides().get(0);
Map<String, XSLFGraphicFrame> chartFramesToRemove = new HashMap<>();
for (XSLFShape shape : slide.getShapes()) {
if (shape instanceof XSLFGraphicFrame) {
XSLFGraphicFrame graphicframe = (XSLFGraphicFrame)shape;
XmlObject xmlobject = graphicframe.getXmlObject();
XmlObject[] graphics = xmlobject.selectPath(
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//a:graphic");
if (graphics.length > 0) { //we have a XSLFGraphicFrame containing a:graphic
XmlObject graphic = graphics[0];
XmlObject[] charts = graphic.selectPath(
"declare namespace c='http://schemas.openxmlformats.org/drawingml/2006/chart' " +
".//c:chart");
if (charts.length > 0) { //we have a XSLFGraphicFrame containing c:chart
XmlObject chart = charts[0];
String rid = chart.selectAttribute(
"http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id")
.newCursor().getTextValue();
chartFramesToRemove.put(rid, graphicframe);
}
}
}
}
PackagePart slidepart = slide.getPackagePart();
OPCPackage opcpackage = slideShow.getPackage();
for (String rid : chartFramesToRemove.keySet()) {
//at frist remove the XSLFGraphicFrame
XSLFGraphicFrame chartFrame = chartFramesToRemove.get(rid);
slide.removeShape(chartFrame);
//Here is the problem in my opinion. This **should** remove all related parts too.
//But since XSLFChart is @Beta, it does not.
//So we try doing removing the related parts manually.
//we get the PackagePart of the chart
PackageRelationship relship = slidepart.getRelationships().getRelationshipByID(rid);
PackagePart chartpart = slidepart.getRelatedPart(relship);
//now we get and remove all the relations and related PackageParts from this chartpart
//this are /ppt/embeddings/Microsoft_Excel_WorksheetN.xlsx, /ppt/charts/colorsN.xml
//and /ppt/charts/styleN.xml
for (PackageRelationship chartrelship : chartpart.getRelationships()) {
String partname = chartrelship.getTargetURI().toString();
PackagePart part = opcpackage.getPartsByName(Pattern.compile(partname)).get(0);
opcpackage.removePart(part);
chartpart.removeRelationship(chartrelship.getId());
}
//this works
//now we **should** be able removing the relationship to the chartpart from the slide too
//but this seems not to be possible
//doing this on PackagePart level works:
slidepart.removeRelationship(rid);
for (PackageRelationship sliderelship : slidepart.getRelationships()) {
System.out.println("rel PP level: " + sliderelship.getTargetURI().toString());
}
//all relationships to /ppt/charts/chartN.xml are removed
//but on POIXMLDocumentPart level this has no effect
for (POIXMLDocumentPart sliderelpart : slide.getRelations()) {
System.out.println("rel POIXML level: " + sliderelpart.getPackagePart().getPartName());
}
//relationships to /ppt/charts/chartN.xml are **not** removed
//So we cannot remove the chartpart.
//If we would do this, then while slideShow.write the
//org.apache.poi.xslf.usermodel.XSLFChart.commit in XSLFChart.java fails
//because after removing the PackagePart is absent but the relation is still there.
//opcpackage.removePart(chartpart);
}
slideShow.write(new FileOutputStream("PPTWithChartsNew.pptx"));
slideShow.close();
}
}
使用< code>PowerPoint打开< code > pptwithchartsnew . pptx 并保存后,不必要的< code >/PPT/charts/stylen . XML 部分也被删除,因为它们之间不再有关系。
2017年9月24日编辑:
找到了使用反射的解决方案。如上所述,删除相关的图表部分需要自上而下,这意味着从POIXLDocumentPart
级别向下到PackagePart
级别。自从<code>POIXLDocumentPart以来。removeRelation</code>是受保护的,我们需要使用反射来实现这一点。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.xmlbeans.XmlObject;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Pattern;
import java.lang.reflect.Method;
public class ReadPPTRemoveChart {
public static void main(String[] args) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("PPTWithCharts.pptx"));
XSLFSlide slide = slideShow.getSlides().get(0);
Map<String, XSLFGraphicFrame> chartFramesToRemove = new HashMap<>();
for (XSLFShape shape : slide.getShapes()) {
if (shape instanceof XSLFGraphicFrame) {
XSLFGraphicFrame graphicframe = (XSLFGraphicFrame)shape;
XmlObject xmlobject = graphicframe.getXmlObject();
XmlObject[] graphics = xmlobject.selectPath(
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
".//a:graphic");
if (graphics.length > 0) { //we have a XSLFGraphicFrame containing a:graphic
XmlObject graphic = graphics[0];
XmlObject[] charts = graphic.selectPath(
"declare namespace c='http://schemas.openxmlformats.org/drawingml/2006/chart' " +
".//c:chart");
if (charts.length > 0) { //we have a XSLFGraphicFrame containing c:chart
XmlObject chart = charts[0];
String rid = chart.selectAttribute(
"http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id")
.newCursor().getTextValue();
chartFramesToRemove.put(rid, graphicframe);
}
}
}
}
PackagePart slidepart = slide.getPackagePart();
OPCPackage opcpackage = slideShow.getPackage();
for (String rid : chartFramesToRemove.keySet()) {
//at frist remove the XSLFGraphicFrame
XSLFGraphicFrame chartFrame = chartFramesToRemove.get(rid);
slide.removeShape(chartFrame);
//Here is the problem in my opinion. This **should** remove all related parts too.
//But since XSLFChart is @Beta, it does not.
//So we try doing removing the related parts manually.
//we get the PackagePart of the chart
PackageRelationship relship = slidepart.getRelationships().getRelationshipByID(rid);
PackagePart chartpart = slidepart.getRelatedPart(relship);
//now we get and remove all the relations and related PackageParts from this chartpart
//this are /ppt/embeddings/Microsoft_Excel_WorksheetN.xlsx, /ppt/charts/colorsN.xml
//and /ppt/charts/styleN.xml
for (PackageRelationship chartrelship : chartpart.getRelationships()) {
String partname = chartrelship.getTargetURI().toString();
PackagePart part = opcpackage.getPartsByName(Pattern.compile(partname)).get(0);
opcpackage.removePart(part);
chartpart.removeRelationship(chartrelship.getId());
}
//now we remove the chart part from the slide part
//We need doing this on POIXMLDocumentPart level.
//Since POIXMLDocumentPart.removeRelation is protected, we need doing this using reflection
XSLFChart chart = (XSLFChart)slide.getRelationById(rid);
Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class);
removeRelation.setAccessible(true);
removeRelation.invoke(slide, chart);
}
slideShow.write(new FileOutputStream("PPTWithChartsNew.pptx"));
slideShow.close();
}
}
我已经设置了一个宏,它将Excel电子表格中的一些图表保存为图片(作为更大程序的一部分),并且需要一些代码来将这些图片(每张幻灯片一张)粘贴到幻灯片中。 目前,我已经成功地打开了一个带有4张空白幻灯片的PowerPoint演示文稿,甚至还没有成功导入1张图片。 我一直在使用形状之类的方法。addpicture(“C:\Users\restoppathname”),但尚未使其工作
我有一个. PPT (PowerPoint,可转换为ODP或PPTX)文件,每张幻灯片上都有演讲者注释。我想将整个演示文稿提取为动态内容,这样我就可以创建一个演讲者备忘单,在我讲话时在手机或桌子上运行(幻灯片缩略图和演讲者注释)。我经常这样做,以至于讨厌手工操作。 这几乎很容易
上下文:C#中的PowerPoint幻灯片有一个属性slide。名称(通常包含任意字符串值)。在我的C#应用程序中,我想使用这个属性来标识幻灯片(幻灯片顺序不可靠)。 问题:如何手动设置幻灯片。PowerPoint应用程序中的Name属性? 我的问题非常像:“如何在PowerPoint幻灯片中命名对象?”,但只是在幻灯片级别上。 任何帮助都将不胜感激。
现在我生成了一组幻灯片,当我以pps形式打开它时,它不会在幻灯片之间转换,除非我在微软的powerpoint编辑器中打开它(我可以在其中添加转换)并保存它。然后它可以正常转换。 我认为这与幻灯片母版有关:https://poi.apache.org/apidocs/org/apache/poi/xslf/usermodel/XSLFSlideMaster.html但我不确定它是如何使用的,因为它说
使用幻灯片组件,你需要在 sm.js 和 sm.css 之后额外引入如下两个文件: <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm-extend.min.css"> <script type='text/javascript' src='//g.alicdn.com/msui/sm/0.6.2/js/sm-exte
我试图在演示文稿中添加幻灯片,但遇到了错误。 上下文:我有一个包含200多页的word文件。每个页面包含一个图像(截图)。我想为MS Word文档中的每个图片创建一个PowerPoint文档;我想将图片粘贴到空白幻灯片中。 我在的行中有一个错误