Я использую Apache POI для замены слов docx. Для нормального абзаца я успеваю использовать XWPFParagraph и XWPFRun для замены слов. Затем я попытался заменить слова в текстовом поле. Я ссылался на этот qaru.site/questions/2274251/... чтобы получить текст в текстовом поле. Я успеваю распечатать текст в консоли. Однако я не смог заменить слова в текстовом поле. Вот некоторые из моих кодов:
for (XWPFParagraph paragraph : doc.getParagraphs()) {
XmlObject[] textBoxObjects = paragraph.getCTP().selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' declare namespace wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape' .//*/wps:txbx/w:txbxContent");
for (int i =0; i < textBoxObjects.length; i++) {
XWPFParagraph embeddedPara = null;
try {
XmlObject[] paraObjects = textBoxObjects[i].
selectChildren(
new QName("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "p"));
for (int j=0; j<paraObjects.length; j++) {
embeddedPara = new XWPFParagraph(CTP.Factory.parse(paraObjects[j].xmlText()), paragraph.getBody());
List<XWPFRun> runs = embeddedPara.getRuns();
for (XWPFRun r : runs) {
String text = r.getText(0);
if (text != null && text.contains(someWords)) {
text = text.replace(someWords, "replaced");
r.setText(text, 0);
}
}
}
} catch (XmlException e) {
//handle
}
}
}
Я думаю, проблема в том, что я создал новый XWPFParagraph embeddedPara и заменил слова embeddedPara, но не исходный абзац. Поэтому после того, как я напишу в файле, слова все равно не меняются.
Как читать и заменять слова в текстовом поле без создания нового XWPFParagraph?
Проблема возникает из-за того, что текстовые поля Word
могут содержаться в нескольких разных XmlObjects
зависящих от версии Word
. Эти XmlObjects
могут также находиться в очень разных пространствах имен. Таким образом, selectChildren
не может следовать маршруту пространства имен и поэтому он вернет XmlAnyTypeImpl
.
Все, что есть у всего текстового поля, состоит в том, что их прогоны находятся на пути .//*/w:txbxContent/w:p/w:r
. Таким образом, мы можем использовать XmlCursor
который выбирает этот путь. Затем мы собираем все выбранные XmlObjects
в List<XmlObject>
. Затем мы анализируем CTR
из этих объектов, которые, конечно, являются только CTR
вне контекста документа. Но мы можем создать XWPFRuns
из тех, сделать замену там, а затем set
содержание XML этих XWPFRuns
обратно к объектам. После этого у нас есть объекты, содержащие замененное содержимое.
Пример:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import java.util.List;
import java.util.ArrayList;
public class WordReplaceTextInTextBox {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordReplaceTextInTextBox.docx"));
String someWords = "TextBox";
for (XWPFParagraph paragraph : document.getParagraphs()) {
XmlCursor cursor = paragraph.getCTP().newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//*/w:txbxContent/w:p/w:r");
List<XmlObject> ctrsintxtbx = new ArrayList<XmlObject>();
while(cursor.hasNextSelection()) {
cursor.toNextSelection();
XmlObject obj = cursor.getObject();
ctrsintxtbx.add(obj);
}
for (XmlObject obj : ctrsintxtbx) {
CTR ctr = CTR.Factory.parse(obj.toString());
XWPFRun bufferrun = new XWPFRun(ctr, (IRunBody)paragraph);
String text = bufferrun.getText(0);
if (text != null && text.contains(someWords)) {
text = text.replace(someWords, "replaced");
bufferrun.setText(text, 0);
}
obj.set(bufferrun.getCTR());
}
}
document.write(new FileOutputStream("WordReplaceTextInTextBoxNew.docx"));
document.close();
}
}
XWPFParagraph
а в созданииCTP
который не зависит от документа. ВашXmlObject[] paraObjects
является массивомXmlObject
который должен бытьinstanceof
CTP
. Так что попробуйте:embeddedPara = new XWPFParagraph((CTP)paraObjects[j], paragraph.getBody());
, Не проверено - поэтому комментарий, а не ответ.embeddedPara = new XWPFParagraph((CTP)paraObjects[j], paragraph.getBody());
, выдать ошибку:Cannot cast org.apache.xmlbeans.impl.values.XmlAnyTypeImpl to org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP
. Я читал ваш ответ раньше, но все еще не знаю, как изменить мой код.