Apache POI:更改应用于错误的幻灯片
Apache POI: Changes applied to the wrong slide
从 Apache POI 3.17 升级到 5.x.
时,我有一个非常奇怪的行为
使用新的 Apache POI 版本,文本替换是在错误的幻灯片上完成的。它修改原始模板幻灯片,而不是在复制的模板上进行修改。
我使用现有的包含“模板”幻灯片的演示文稿。复制此模板幻灯片,然后替换某些文本。这与旧版本完美配合。
这里是我用来创建模板幻灯片副本的代码:
SlideShow slides = new XMLSlideShow(inputStream);
XSLFSlide template = slides.getSlides().get(SLIDE_INDEX_TEMPLATE);
XSLFSlide newSlide = slides.createSlide(template.getSlideLayout());
newSlide.importContent(template);
这里是文本替换的简化版本:
for (XSLFShape shape: slide) {
if (shape instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape) shape;
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
List<XSLFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(XSLFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (XSLFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
}
}
知道我做错了什么或 Apache POI 中的任何更改可能会破坏它吗?
自从 apache poi 4
以来,apache 开发人员决定对文本段落使用 org.apache.poi.xddf.usermodel.text.*
,并且文本也在 XSLF
中运行。最多 apache poi 3.17
XSLF
有自己的 类 用于文本段落和文本运行。这些进一步存在(可能是为了向后兼容),但在大于 apache po 3.17
的版本中,当从其他幻灯片复制文本形状时,它们使用了错误的文本正文。我还没有找到发生这种情况的确切位置,但下面显示这是真的。
完整示例:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import java.util.*;
import java.util.stream.*;
public class PPTXCCopyTemplateSlideAndChange {
static final int SLIDE_INDEX_TEMPLATE = 0;
public static void main(String[] args) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("./PPTXIn.pptx"));
XSLFSlide template = slideShow.getSlides().get(SLIDE_INDEX_TEMPLATE);
XSLFSlide newSlide = slideShow.createSlide(template.getSlideLayout());
newSlide = newSlide.importContent(template);
for (XSLFShape shape: newSlide) {
if (shape instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape) shape;
//textShape.setText("Replaced!"); // this would work using apache poi 3.17 as well as using apache poi 5.2.2
/* this works using apache poi 3.17 only but uses the wrong text body in version 5
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
List<XSLFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(XSLFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (XSLFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
*/
///* this works using apache poi 5.2.2 only but cannot work using version 3.17 because of usage of org.apache.poi.xddf.usermodel.text.*
List<org.apache.poi.xddf.usermodel.text.XDDFTextParagraph> textBoxParagraphs = textShape.getTextBody().getParagraphs();
List<org.apache.poi.xddf.usermodel.text.XDDFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(org.apache.poi.xddf.usermodel.text.XDDFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (org.apache.poi.xddf.usermodel.text.XDDFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
//*/
}
}
FileOutputStream out = new FileOutputStream("./PPTXOut.pptx");
slideShow.write(out);
out.close();
}
}
此处 textShape.setText("Replaced!");
使用 apache poi 3.17
和 apache poi 5.2.2
一样有效,因为 XSLFTextShape.setText
即使在版本 5 中也直接使用基础 CTTextBody
。当然使用它你无法控制不同的文本运行。
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
仅使用 apache poi 3.17
有效,但在版本 5 中使用了错误的文本正文。可能是因为 XSLFAutoShape.getTextBody(boolean create)
也使用 org.apache.poi.xddf.usermodel.text.XDDFTextBody
而不是仅使用基础 CTTextBody
直接。但不太确定。
List<org.apache.poi.xddf.usermodel.text.XDDFTextParagraph> textBoxParagraphs = textShape.getTextBody().getParagraphs();
仅适用于 apache poi 5.2.2
但无法使用 3.17 版,因为使用了 3.17 版中未知的 org.apache.poi.xddf.usermodel.text.*
。
因此,您必须为不同版本的 apache poi
编写完全不同的代码。没有向后兼容性,甚至可能在这里尝试过。
从 Apache POI 3.17 升级到 5.x.
时,我有一个非常奇怪的行为使用新的 Apache POI 版本,文本替换是在错误的幻灯片上完成的。它修改原始模板幻灯片,而不是在复制的模板上进行修改。
我使用现有的包含“模板”幻灯片的演示文稿。复制此模板幻灯片,然后替换某些文本。这与旧版本完美配合。
这里是我用来创建模板幻灯片副本的代码:
SlideShow slides = new XMLSlideShow(inputStream);
XSLFSlide template = slides.getSlides().get(SLIDE_INDEX_TEMPLATE);
XSLFSlide newSlide = slides.createSlide(template.getSlideLayout());
newSlide.importContent(template);
这里是文本替换的简化版本:
for (XSLFShape shape: slide) {
if (shape instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape) shape;
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
List<XSLFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(XSLFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (XSLFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
}
}
知道我做错了什么或 Apache POI 中的任何更改可能会破坏它吗?
自从 apache poi 4
以来,apache 开发人员决定对文本段落使用 org.apache.poi.xddf.usermodel.text.*
,并且文本也在 XSLF
中运行。最多 apache poi 3.17
XSLF
有自己的 类 用于文本段落和文本运行。这些进一步存在(可能是为了向后兼容),但在大于 apache po 3.17
的版本中,当从其他幻灯片复制文本形状时,它们使用了错误的文本正文。我还没有找到发生这种情况的确切位置,但下面显示这是真的。
完整示例:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import java.util.*;
import java.util.stream.*;
public class PPTXCCopyTemplateSlideAndChange {
static final int SLIDE_INDEX_TEMPLATE = 0;
public static void main(String[] args) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("./PPTXIn.pptx"));
XSLFSlide template = slideShow.getSlides().get(SLIDE_INDEX_TEMPLATE);
XSLFSlide newSlide = slideShow.createSlide(template.getSlideLayout());
newSlide = newSlide.importContent(template);
for (XSLFShape shape: newSlide) {
if (shape instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape) shape;
//textShape.setText("Replaced!"); // this would work using apache poi 3.17 as well as using apache poi 5.2.2
/* this works using apache poi 3.17 only but uses the wrong text body in version 5
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
List<XSLFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(XSLFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (XSLFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
*/
///* this works using apache poi 5.2.2 only but cannot work using version 3.17 because of usage of org.apache.poi.xddf.usermodel.text.*
List<org.apache.poi.xddf.usermodel.text.XDDFTextParagraph> textBoxParagraphs = textShape.getTextBody().getParagraphs();
List<org.apache.poi.xddf.usermodel.text.XDDFTextRun> textBoxParagraphTextRuns = textBoxParagraphs.stream().map(org.apache.poi.xddf.usermodel.text.XDDFTextParagraph::getTextRuns).flatMap(List::stream).collect(Collectors.toList());
for (org.apache.poi.xddf.usermodel.text.XDDFTextRun r : textBoxParagraphTextRuns) {
r.setText("Replaced!");
}
//*/
}
}
FileOutputStream out = new FileOutputStream("./PPTXOut.pptx");
slideShow.write(out);
out.close();
}
}
此处 textShape.setText("Replaced!");
使用 apache poi 3.17
和 apache poi 5.2.2
一样有效,因为 XSLFTextShape.setText
即使在版本 5 中也直接使用基础 CTTextBody
。当然使用它你无法控制不同的文本运行。
List<XSLFTextParagraph> textBoxParagraphs = textShape.getTextParagraphs();
仅使用 apache poi 3.17
有效,但在版本 5 中使用了错误的文本正文。可能是因为 XSLFAutoShape.getTextBody(boolean create)
也使用 org.apache.poi.xddf.usermodel.text.XDDFTextBody
而不是仅使用基础 CTTextBody
直接。但不太确定。
List<org.apache.poi.xddf.usermodel.text.XDDFTextParagraph> textBoxParagraphs = textShape.getTextBody().getParagraphs();
仅适用于 apache poi 5.2.2
但无法使用 3.17 版,因为使用了 3.17 版中未知的 org.apache.poi.xddf.usermodel.text.*
。
因此,您必须为不同版本的 apache poi
编写完全不同的代码。没有向后兼容性,甚至可能在这里尝试过。