Java 在dotx/docx文件中编辑头
我目前正试图从现有的dotx格式模板生成一个新的docx文件。我想更改标题中的firstname、lastname等,但由于某些原因我无法访问它们。。。 我的做法如下:Java 在dotx/docx文件中编辑头,java,apache-poi,apache-poi-4,Java,Apache Poi,Apache Poi 4,我目前正试图从现有的dotx格式模板生成一个新的docx文件。我想更改标题中的firstname、lastname等,但由于某些原因我无法访问它们。。。 我的做法如下: public void generateDocX(Long id) throws IOException, InvalidFormatException { //Get user per id EmployeeDTO employeeDTO = employeeService.getEmployee(id);
public void generateDocX(Long id) throws IOException, InvalidFormatException {
//Get user per id
EmployeeDTO employeeDTO = employeeService.getEmployee(id);
//Location where the new docx file will be saved
FileOutputStream outputStream = new FileOutputStream(new File("/home/user/Documents/project/src/main/files/" + employeeDTO.getId() + "header.docx"));
//Get the template for generating the new docx file
File template = new File("/home/user/Documents/project/src/main/files/template.dotx");
OPCPackage pkg = OPCPackage.open(template);
XWPFDocument document = new XWPFDocument(pkg);
for (XWPFHeader header : document.getHeaderList()) {
List<XWPFParagraph> paragraphs = header.getParagraphs();
System.out.println("Total paragraphs in header are: " + paragraphs.size());
System.out.println("Total elements in the header are: " + header.getBodyElements().size());
for (XWPFParagraph paragraph : paragraphs) {
System.out.println("Paragraph text is: " + paragraph.getText());
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String runText = run.getText(run.getTextPosition());
System.out.println("Run text is: " + runText);
}
}
}
//Write the changes to the new docx file and close the document
document.write(outputStream);
document.close();
}
控制台中的输出为1、null或空字符串。。。我已经尝试了好几种方法,但是没有任何运气
下面是template.dotx中的内容
并且只获取直接在IBody中的段落或正文元素。但是你的段落不是直接在那里,而是在一个单独的文本框或文本框中。这就是为什么他们不能通过这种方式得到
由于*.docx是一个ZIP归档文件,包含用于文档、页眉和页脚的jgxml文件,因此可以通过创建一个选择所有w:rxml元素的XmlCursor来获取一个IBody的所有文本运行。对于XWPFHeader,这可能看起来是这样的:
private List<XmlObject> getAllCTRs(XWPFHeader header) {
CTHdrFtr ctHdrFtr = header._getHdrFtr();
XmlCursor cursor = ctHdrFtr.newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//*/w:r");
List<XmlObject> ctrInHdrFtr = new ArrayList<XmlObject>();
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
XmlObject obj = cursor.getObject();
ctrInHdrFtr.add(obj);
}
return ctrInHdrFtr;
}
现在,我们有了该IBody中所有XML元素的列表,它们是Word中的文本运行元素
有了这些,我们可以像这样从他们身上获得文本:
private void printAllTextInTextRunsOfIBody(IBody iBody) throws Exception {
List<XmlObject> ctrInIBody = getAllCTRs(iBody);
for (XmlObject obj : ctrInIBody) {
CTR ctr = CTR.Factory.parse(obj.xmlText());
for (CTText ctText : ctr.getTList()) {
String text = ctText.getStringValue();
System.out.println(text);
}
}
}
顺便说一句:由于您的文档是从*.dotx打开的,因此需要将内容类型从wordprocessingml.template更改为wordprocessingml.document。否则Word将不会打开生成的*.docx文档。看
由于我对替换占位符文本的方法持怀疑态度,我更喜欢的方法是填写表单。看见当然,这样的表单字段不能在页眉或页脚中使用。因此,页眉或页脚可以从整体上从头开始创建。只获取直接位于该IBody中的段落或正文元素。但是你的段落不是直接在那里,而是在一个单独的文本框或文本框中。这就是为什么他们不能通过这种方式得到
由于*.docx是一个ZIP归档文件,包含用于文档、页眉和页脚的jgxml文件,因此可以通过创建一个选择所有w:rxml元素的XmlCursor来获取一个IBody的所有文本运行。对于XWPFHeader,这可能看起来是这样的:
private List<XmlObject> getAllCTRs(XWPFHeader header) {
CTHdrFtr ctHdrFtr = header._getHdrFtr();
XmlCursor cursor = ctHdrFtr.newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//*/w:r");
List<XmlObject> ctrInHdrFtr = new ArrayList<XmlObject>();
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
XmlObject obj = cursor.getObject();
ctrInHdrFtr.add(obj);
}
return ctrInHdrFtr;
}
现在,我们有了该IBody中所有XML元素的列表,它们是Word中的文本运行元素
有了这些,我们可以像这样从他们身上获得文本:
private void printAllTextInTextRunsOfIBody(IBody iBody) throws Exception {
List<XmlObject> ctrInIBody = getAllCTRs(iBody);
for (XmlObject obj : ctrInIBody) {
CTR ctr = CTR.Factory.parse(obj.xmlText());
for (CTText ctText : ctr.getTList()) {
String text = ctText.getStringValue();
System.out.println(text);
}
}
}
顺便说一句:由于您的文档是从*.dotx打开的,因此需要将内容类型从wordprocessingml.template更改为wordprocessingml.document。否则Word将不会打开生成的*.docx文档。看
由于我对替换占位符文本的方法持怀疑态度,我更喜欢的方法是填写表单。看见当然,这样的表单字段不能在页眉或页脚中使用。所以页眉或页脚可以从头开始创建。我认为实际上,firstname、lastname等所在的框是一个框架内容,或者至少Libre Office是这么说的,当我点击它时。我认为实际上,firstname所在的框,lastname等是一个框架内容,或者至少Libre Office是这么说的,当我点击它时..谢谢你的回复!我已经尝试了你提供的代码,但由于某种原因什么都没有发生。。。实际上,打印头printalTextIntextRunSofHeader运行中的文本的方法根本不打印任何内容。我发现第二个for循环实际上从未执行过。。有没有进一步的建议,或者您认为自己重新创建模板会更好?我不确定我是否会做得更好,但我可以试试@IvanNickSim:也许文本框甚至不在标题中,而是在文档中,只放在标题上?请参阅我的答案中的补充。我将在一分钟内尝试您的更改。。我已经检查了docx文件中的内容,并用一张图片更新了我的帖子。@Alex非常感谢你,伙计!在您所做的更改之后,现在名、姓和职称都已成功更改!我想我也必须对页脚和其他页眉做同样的处理,因为它们也是不同的文档。。我说得对吗?@IvanNickSim:是的,你说得对。由于您已经解压了*.dotx,您已经看到了不同的文档部分。以下部分包含文本运行:document.xml是文档正文,headerN.xml和footerN.xml是不同的页眉和页脚默认值,甚至,首先,endnotes.xml包含尾注文本,footnotes.xml包含脚注文本。感谢您的回复!我已经尝试了你提供的代码,但由于某种原因什么都没有发生。。。实际上,打印头printalTextIntextRunSofHeader运行中的文本的方法根本不打印任何内容。我发现第二个for循环实际上从未执行过。。有没有进一步的建议,或者您认为自己重新创建模板会更好?我不确定我是否会做得更好,但我可以试试@IvanNickSim:也许文本框甚至不在标题中,而是在文档中,只放在标题上?请参阅我的答案中的补充。我将在一分钟内尝试您的更改。。我已经检查了docx文件中的内容,并用
一张照片里面是什么…@Alex非常感谢你,伙计!在您所做的更改之后,现在名、姓和职称都已成功更改!我想我也必须对页脚和其他页眉做同样的处理,因为它们也是不同的文档。。我说得对吗?@IvanNickSim:是的,你说得对。由于您已经解压了*.dotx,您已经看到了不同的文档部分。以下部分包含文本运行:document.xml是文档正文,headerN.xml和footerN.xml是不同的页眉和页脚默认值,甚至,首先,endnotes.xml包含尾注文本,footnotes.xml包含脚注文本。