我想使用apache poi以编程方式对现有Word文档写评论。我已经成功地通过method mentioned here在段落中添加了注释,但是在向表中添加注释时,我不知道如何将其与真实注释相关联
BigInteger cId = BigInteger.ZERO;
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("The first comment.");
ctComment.setId(cId);
paragraph = document.createParagraph();
paragraph.getCTP().addNewCommentRangeStart().setId(cId);
run = paragraph.createRun();
run.setText("Paragraph with the first comment.");
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
在段落中,我们可以使用paragraph.getCTP().addNewR().addNewCommentReference().setId()
来链接注释,但是表中似乎没有类似的方法。我该怎么办?我是apoi poi的初学者,任何建议都将不胜感激。
答案 0 :(得分:0)
关于如何注释整个表的问题的简短答案是:在该表的第一个单元格中获得第一段,将CommentRangeStart
设置为该段的第一元素。然后,您将获得该表最后一个单元格中的最后一个段落,以将CommentRangeEnd
设置为该段落中的最后一个元素。
但是,如果您想更改已经存在的Word
文档,则需要考虑更多内容。如果已经有评论该怎么办?您要链接的示例是从头开始创建新 Word
文档。因此,以前不能有评论。我还提供了How to manipulate content of a comment with Apache POI。但这依赖于已经存在的评论。现在我们必须结合使用两者。这需要考虑已经存在的注释以及尚未存在的注释文档,然后再重新创建。
此外,很难将CommentRangeStart
设置为已经存在的段落中的第一个元素。没有为此的方法。因此,我们需要使用非常低级的XML
操纵来实现这一目标。
以下示例需要一个WordDocument.docx
至少有一个表。然后整个表都会被评论。
import java.io.*;
import org.apache.poi.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.xmlbeans.*;
import org.apache.poi.xwpf.usermodel.*;
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import javax.xml.namespace.QName;
import java.math.BigInteger;
import java.util.GregorianCalendar;
import java.util.Locale;
public class WordCommentWholeTable {
//a method to get or create the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document) throws Exception {
MyXWPFCommentsDocument myXWPFCommentsDocument = null;
//trying to get the CommentsDocument
for (POIXMLDocumentPart.RelationPart rpart : document.getRelationParts()) {
String relation = rpart.getRelationship().getRelationshipType();
if (relation.equals(XWPFRelation.COMMENT.getRelation())) {
POIXMLDocumentPart part = rpart.getDocumentPart();
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part.getPackagePart());
String rId = document.getRelationId(part);
document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
}
//create a new CommentsDocument if there is not one already
if (myXWPFCommentsDocument == null) {
OPCPackage oPCPackage = document.getPackage();
PackagePartName partName = PackagingURIHelper.createPartName("/word/comments.xml");
PackagePart part = oPCPackage.createPart(
partName,
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part);
document.addRelation(null, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
return myXWPFCommentsDocument;
}
//a method to get the next comment Id from CTComments
private static BigInteger getCommentId(CTComments comments) {
BigInteger cId = BigInteger.ZERO;
for (CTComment ctComment : comments.getCommentList()) {
if (ctComment.getId().compareTo(cId) == 1) {
cId = ctComment.getId();
}
}
cId = cId.add(BigInteger.ONE);
return cId;
}
//method to set CommentRangeStart as first element in paragraph
private static CTMarkupRange insertCommentRangeStartAsFirstElement(XWPFParagraph paragraph) {
String uri = CTMarkupRange.type.getName().getNamespaceURI();
String localPart = "commentRangeStart";
XmlCursor cursor = paragraph.getCTP().newCursor();
cursor.toFirstChild();
cursor.beginElement(localPart, uri);
cursor.toParent();
CTMarkupRange commentRangeStart = (CTMarkupRange)cursor.getObject();
cursor.dispose();
return commentRangeStart;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordDocument.docx"));
MyXWPFCommentsDocument myXWPFCommentsDocument = createCommentsDocument(document);
CTComments comments = myXWPFCommentsDocument.getComments();
CTComment ctComment;
XWPFParagraph paragraph;
XWPFRun run;
//comment for the table
BigInteger cId = getCommentId(comments);
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("This is a comment for whole table.");
ctComment.setId(cId);
//get first paragraph in first table cell to set CommentRangeStart
XWPFTable table = document.getTables().get(0);
XWPFTableRow row = table.getRow(0);
XWPFTableCell cell = row.getCell(0);
paragraph = cell.getParagraphArray(0);
CTMarkupRange commentRangeStart = insertCommentRangeStartAsFirstElement(paragraph);
commentRangeStart.setId(cId);
//get last paragraph in last table cell to set CommentRangeEnd and CommentReference
row = table.getRows().get(table.getRows().size()-1);
cell = row.getTableCells().get(row.getTableCells().size()-1);
paragraph = cell.getParagraphs().get(cell.getParagraphs().size()-1);
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
FileOutputStream out = new FileOutputStream("WordDocumentWithComments.docx");
document.write(out);
out.close();
document.close();
}
//a wrapper class for the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static class MyXWPFCommentsDocument extends POIXMLDocumentPart {
private CTComments comments;
private MyXWPFCommentsDocument(PackagePart part) throws Exception {
super(part);
try {
comments = CommentsDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getComments();
} catch (Exception ex) {
// there was no comments yet
}
if (comments == null) comments = CommentsDocument.Factory.newInstance().addNewComments();
}
private CTComments getComments() {
return comments;
}
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTComments.type.getName().getNamespaceURI(), "comments"));
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
comments.save(out, xmlOptions);
out.close();
}
}
}