当前位置: 首页 > 知识库问答 >
问题:

替换。docx(Apache POI、Docx4j或其他)中的文本模板

冯良才
2023-03-14
Example: 
 …, с одной стороны, и %SOME_TEXT% именуемое в дальнейшем «Заказчик», в 
 лице  %SOME_TEXT%   действующего на основании %SOME_TEXT% с другой стороны, 
 заключили настоящий Договор о нижеследующем: …
…
, с одной стороны, и 
%
SOME_TEXT
%

именуемое 
в дальнейшем «Заказчик», в лице

%
SOME
_
TEXT
%

代码示例:

FileInputStream fis = new FileInputStream(new File("document.docx"));
XWPFDocument document = new XWPFDocument(fis);
List<XWPFParagraph> paragraphs = document.getParagraphs();
paragraphs.forEach(para -> {
    para.getRuns().forEach(run -> {
        String text = run.getText(0);
        if (text != null) {
           System.out.println(text);
           // text replacement process
           // run.setText(newText,0);
        }
    });
});

我发现了许多类似的问题(比如“替换Apache POI XWPF中的文本”),但没有找到我的问题的答案(这里的答案“Apache POI XWPFRun对象中的分离文本行”提供了不方便的解决方案)。

我尝试使用docx4j,这个示例=>“docx4j find and replace”,但是docx4j的工作原理与此相似。

WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File("test.docx"));
HashMap<String, String> mappings = new HashMap<>();
VariablePrepare.prepare(wordMLPackage);//see notes
mappings.put("SOME_TEXT", "XXXX");
wordMLPackage.getMainDocumentPart().variableReplace(mappings);
wordMLPackage.save(new File("out.docx"));
Input:
…, с одной стороны, и ${SOME_TEXT} именуемое в дальнейшем «Заказчик» ...
Output:
…, с одной стороны, и SOME_TEXT именуемое в дальнейшем «Заказчик» ...
<w:r>
   <w:t xml:space="preserve">, с одной стороны, и </w:t>
</w:r>
<w:r><w:t>$</w:t></w:r>
<w:r><w:t>{</w:t></w:r>
<w:r>
    <w:rPr>
       <w:rFonts w:eastAsia="Times-Roman"/>
          <w:color w:val="000000" w:themeColor="text1"/>
          <w:lang w:val="en-US"/>
    </w:rPr>
    <w:t>SOME</w:t>        <!-- First part of template: "SOME" -->
</w:r>
<w:r>
    <w:rPr>
        <w:rFonts w:eastAsia="Times-Roman"/>
        <w:color w:val="000000" w:themeColor="text1"/>
    </w:rPr>
    <w:t>_</w:t>           <!-- Second part of template: "_"   -->
</w:r>
<w:r>
    <w:rPr>
        <w:rFonts w:eastAsia="Times-Roman"/>
        <w:color w:val="000000" w:themeColor="text1"/>
        <w:lang w:val="en-US"/>
    </w:rPr>
    <w:t>TEXT</w:t>        <!-- Third part of template: "TEXT" -->
</w:r>
<w:r>
    <w:rPr>
        <w:rFonts w:eastAsia="Times-Roman"/>
        <w:color w:val="000000" w:themeColor="text1"/>
    </w:rPr>
    <w:t>}</w:t>
</w:r>

,那个模板位于不同的xml标记中,我不明白为什么...

请帮助我找到方便的方法来替换文本......

共有1个答案

金承嗣
2023-03-14

正如您所看到的,“使用正则表达式(java RegEx)在MS Word(.docx)文档中进行替换”的方法并不是很好,因为您永远无法确定要替换的文本将在一个文本运行中一起进行。更好的方法是在Word中使用字段(合并字段或表单字段)或内容控件。

对于这样的需求,我最喜欢的仍然是Word中的旧表单字段。

第一个优点是,即使没有文档保护,也不可能对表单字段内容的部分进行不同的格式化,从而将表单字段内容分成不同的运行(但请参见注释1)。第二个优点是,由于灰色背景,表单字段在文档内容中是很好的可见性。另一个优点是可以应用文档保护,这样即使在Word的GUI中也只能填充表单字段。这对于保存这样的合同文件以避免不必要的更改是非常好的。

<xml-fragment w:rsidR="00833656" 
  ...
 xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
 ... >
  <w:rPr>
    <w:rFonts w:eastAsia="Times-Roman"/>
    <w:color w:themeColor="text1" w:val="000000"/>
    <w:lang w:val="en-US"/>
  </w:rPr>
    <w:fldChar w:fldCharType="begin">
      <w:ffData>
        <w:name w:val="Text1"/>
        <w:enabled w:val="0"/>
        <w:calcOnExit w:val="0"/>
        <w:textInput>
          <w:default w:val="<введите заказчика>"/>
        </w:textInput>
      </w:ffData>
    </w:fldChar>
  </xml-fragment>
</xml-fragment>
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.apache.xmlbeans.SimpleValue;
import javax.xml.namespace.QName;

public class WordReplaceTextInFormFields {

 private static void replaceFormFieldText(XWPFDocument document, String ffname, String text) {
  boolean foundformfield = false;
  for (XWPFParagraph paragraph : document.getParagraphs()) {
   for (XWPFRun run : paragraph.getRuns()) {
    XmlCursor cursor = run.getCTR().newCursor();
    cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:fldChar/@w:fldCharType");
    while(cursor.hasNextSelection()) {
     cursor.toNextSelection();
     XmlObject obj = cursor.getObject();
     if ("begin".equals(((SimpleValue)obj).getStringValue())) {
      cursor.toParent();
      obj = cursor.getObject();
      obj = obj.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:ffData/w:name/@w:val")[0];
      if (ffname.equals(((SimpleValue)obj).getStringValue())) {
       foundformfield = true;
      } else {
       foundformfield = false;
      }
     } else if ("end".equals(((SimpleValue)obj).getStringValue())) {
      if (foundformfield) return;
      foundformfield = false;
     }
    }
    if (foundformfield && run.getCTR().getTList().size() > 0) {
     run.getCTR().getTList().get(0).setStringValue(text);
//System.out.println(run.getCTR());
    }
   }
  }
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));

  replaceFormFieldText(document, "Text1", "Моя Компания");
  replaceFormFieldText(document, "Text2", "Аксель Джоачимович Рихтер");
  replaceFormFieldText(document, "Text3", "Доверенность");

  FileOutputStream out = new FileOutputStream("WordReplaceTextInFormFields.docx");
  document.write(out);
  out.close();
  document.close();
 }
}
 类似资料:
  • 编辑:我发现如果我向UnmarshallFromTemplate.docx添加一些文本并保存它,它不会替换新的文本行。-标记以某种方式拆分为多个标记: 编辑document.xml中的文本并添加缺少的信息没有多大帮助。 编辑2: 伙计们。我找到了一个非常适合自己的解决办法,不知道为什么花了这么长时间才弄明白。正如我所说的:运行在哪里分裂,原因是在我看来是${}。因此,我只是在占位符之前使用了一个#

  • 我无法使用ApachePOI删除docx文件中的所有注释。有没有其他方法可以使用docx4j api删除注释?

  • 我从这里得到代码:Docx4j从一个. docx导出样式,并在另一个. docx中使用它 所以我从模板导入样式。docx,我在那里创建了自己的Heading1 ant标题样式。其工作,我在以下代码中有问题: 如果我添加了这个光谱仪,在创建的. docx文件中,标题样式将是默认的docx4j样式,但是Heading1将与template.docx.中的相同。如果我将“标题”更改为“标题1”,我有同样

  • 我认为问题是我创建了一个新的XWPFparage,embeddedPara,它替换了embeddedPara的单词,而不是origin段落。所以我写了一个档案之后,字还是没变。 如何阅读并替换文本框中的单词,而不创建一个新的XWPF段落?

  • 我正在尝试创建一个包含多列的word文档。这样做(而不是使用表)的原因是,数据将跨越多个页面,在添加到新页面之前,我只能用列填充整个页面。 可以用ApachePOI实现吗?谢谢

  • (*来自http://www.docx4java.org/forums/xhtml-import-f28/html-docx-html-inserts-a-lot-of-space-t1966.html#p6791?sid=78b64a02482926c4dbdbbafbf50d0a914将在应答时更新) 我已经创建了一个html测试文档,其内容如下: 然后,我的代码从这个html创建一个docx