Замените текст в текстовом поле docx, используя Apache POI

2

Я использую 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?

  • 1
    См. Stackoverflow.com/questions/35459386/… . Проблема не в создании нового XWPFParagraph а в создании CTP который не зависит от документа. Ваш XmlObject[] paraObjects является массивом XmlObject который должен быть instanceof CTP . Так что попробуйте: embeddedPara = new XWPFParagraph((CTP)paraObjects[j], paragraph.getBody()); , Не проверено - поэтому комментарий, а не ответ.
  • 0
    @AxelRichter TriededdedPara embeddedPara = new XWPFParagraph((CTP)paraObjects[j], paragraph.getBody()); , выдать ошибку: Cannot cast org.apache.xmlbeans.impl.values.XmlAnyTypeImpl to org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP . Я читал ваш ответ раньше, но все еще не знаю, как изменить мой код.
Показать ещё 1 комментарий
Теги:
ms-word
apache-poi

1 ответ

6
Лучший ответ

Проблема возникает из-за того, что текстовые поля Word могут содержаться в нескольких разных XmlObjects зависящих от версии Word. Эти XmlObjects могут также находиться в очень разных пространствах имен. Таким образом, selectChildren не может следовать маршруту пространства имен и поэтому он вернет XmlAnyTypeImpl.

Все, что есть у всего текстового поля, состоит в том, что их прогоны находятся на пути .//*/w:txbxContent/w:p/w:r. Таким образом, мы можем использовать XmlCursor который выбирает этот путь. Затем мы собираем все выбранные XmlObjects в List<XmlObject>. Затем мы анализируем CTR из этих объектов, которые, конечно, являются только CTR вне контекста документа. Но мы можем создать XWPFRuns из тех, сделать замену там, а затем set содержание XML этих XWPFRuns обратно к объектам. После этого у нас есть объекты, содержащие замененное содержимое.

Пример:

Изображение 174551

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();
 }
}

Изображение 174551

  • 0
    Это работает, и ваше объяснение понятно. Большое спасибо!
  • 0
    Он извлекает один и тот же текст дважды для меня. Ты знаешь почему?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню