Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用ApachePOI向特定word或在docx文档中运行添加注释_Java_Apache Poi - Fatal编程技术网

Java 使用ApachePOI向特定word或在docx文档中运行添加注释

Java 使用ApachePOI向特定word或在docx文档中运行添加注释,java,apache-poi,Java,Apache Poi,我的目标是在word.docx文档中搜索一个单词或短语,并向其添加注释。我一直在参考找到的示例代码,以及使用ApachePOI添加注释。但是,这三个示例都是在整个段落(甚至整个表格)中添加注释,而不是在特定的单词或run中添加注释 我已尝试在运行级别创建XML游标,但无法将其强制转换为必要的CTMarkupRange以应用注释的开头和结尾 // Create comment BigInteger cId = getCommentId

我的目标是在word.docx文档中搜索一个单词或短语,并向其添加注释。我一直在参考找到的示例代码,以及使用ApachePOI添加注释。但是,这三个示例都是在整个段落(甚至整个表格)中添加注释,而不是在特定的单词或run中添加注释

我已尝试在运行级别创建XML游标,但无法将其强制转换为必要的CTMarkupRange以应用注释的开头和结尾

        // Create comment
                        BigInteger cId = getCommentId(comments);
                        ctComment = comments.addNewComment();
                        ctComment.setAuthor("John Smith");
                        ctComment.setInitials("JS");
                        ctComment.setDate(new GregorianCalendar(Locale.getDefault()));
                        ctComment.addNewP().addNewR().addNewT().setStringValue("Test Comment");
                        ctComment.setId(cId);
                        
        // Set CommentRangeStart
                        String uri = CTMarkupRange.type.getName().getNamespaceURI();
                        String localPart = "commentRangeStart";

                        // XmlCursor cursor = p.getCTP().newCursor();
                        XmlCursor cursor = r.getCTR().newCursor();  
                        cursor.toFirstChild();
                        cursor.beginElement(localPart, uri);
                        cursor.toParent();
                        CTMarkupRange commentRangeStart =  (CTMarkupRange) cursor.getObject(); // This line throws a ClassCastException error
                        cursor.dispose();

                        commentRangeStart.setId(cId);

        // Set CommentRangeEnd and CommentReference

                        p.getCTP().addNewCommentRangeEnd().setId(cId);
                        // p.getCTP().addNewR().addNewCommentReference().setId(cId);
                        r.getCTR().addNewCommentReference().setId(cId);
EDIT1:显示循环运行逻辑的代码段

for(XWPFParagraph p:paragraphs){
    List<XWPFRun> runs = p.getRuns();
    if (runs.size() > 0) {
        for (XWPFRun r : runs) {
            String text = r.getText(0);
            for (Map.Entry<String, List<String>> entry : rules.entrySet()) {
                String key = entry.getKey();
                List<String> value = entry.getValue();

                for (int i = 0; i < value.size(); i++) {
                    if (text != null && regexContains(text, value.get(i))) {
                        // Create comment
                        BigInteger cId = getCommentId(comments);
                        ctComment = comments.addNewComment();
                        ctComment.setAuthor("John Smith");
                        ctComment.setInitials("JS");
                        ctComment.setDate(new GregorianCalendar(Locale.getDefault()));
                        ctComment.addNewP().addNewR().addNewT().setStringValue(key);
                        ctComment.setId(cId);

                        // New snippet from Axel Richter
                        p.getCTP().addNewCommentRangeStart().setId(cId);
                        

                        p.getCTP().addNewCommentRangeEnd().setId(cId);
                        p.getCTP().addNewR().addNewCommentReference().setId(cId);
                    }
                }
            }
        }
    }

}
for(XWPFParagraph p:段落){
List runs=p.getRuns();
如果(运行.size()>0){
用于(XWPFRun r:运行){
String text=r.getText(0);
for(Map.Entry:rules.entrySet()){
String key=entry.getKey();
列表值=entry.getValue();
对于(int i=0;i
这并不像你想象的那么困难

若要对段落内的运行进行注释,需要在段落中的文本运行开始之前设置注释范围开始。需要在段落中文本运行结束后设置注释范围结束。这正是我的代码示例已经做过的。当然,我的代码示例中的所有段落都只运行了一个文本

在下面的完整示例中,第二条注释仅注释“second”一词。为此,该段落有三段文字。第一个文本为“带段落”,第二个文本为“第二个”并有注释,第三个文本为“注释”


这并不像你想象的那么困难

若要对段落内的运行进行注释,需要在段落中的文本运行开始之前设置注释范围开始。需要在段落中文本运行结束后设置注释范围结束。这正是我的代码示例已经做过的。当然,我的代码示例中的所有段落都只运行了一个文本

在下面的完整示例中,第二条注释仅注释“second”一词。为此,该段落有三段文字。第一个文本为“带段落”,第二个文本为“第二个”并有注释,第三个文本为“注释”


嗨Axel,感谢您的详细回复和示例代码。我知道在文本运行之前必须设置“.addNewCommentRangeStart()”,但我仍然在为我的“搜索和注释”工具的逻辑而挣扎。目前,我循环浏览每一段和每一段,并使用模式/匹配器查找与字符串匹配的内容。当我找到一个匹配的跑步记录时,我想给这个特定的跑步记录添加一条注释。但是,我假设我需要在运行之前添加注释范围起始标记?如果您有任何需要纠正我的逻辑的地方,我将不胜感激。谢谢。为了便于参考,我在原始postMy代码中添加了一个逻辑片段,仅用于在创建新段落和文本运行时在新的
XWPFDocument
中创建注释。将特殊位置的注释添加到现有文档中是一项非常复杂的任务。这不是一个问题可以回答的问题,因为这里有多个问题:在一个位置插入?那么:如何在文档中找到起始和结束位置?如果找到,如何在这些位置插入注释范围标记?评论一个现有的单词?然后:如何将单个单词放入自己的文本运行中,并在该文本运行之前和之后插入注释范围标记?嗨,Axel,感谢您的详细回复和示例代码。我知道在文本运行之前必须设置“.addNewCommentRangeStart()”,但我仍然在为我的“搜索和注释”工具的逻辑而挣扎。目前,我循环浏览每一段和每一段,并使用模式/匹配器查找与字符串匹配的内容。当我找到一个匹配的跑步记录时,我想给这个特定的跑步记录添加一条注释。但是,我假设我需要在运行之前添加注释范围起始标记?如果您有任何需要纠正我的逻辑的地方,我将不胜感激。谢谢。为了便于参考,我在原始postMy代码中添加了一个逻辑片段,仅用于在创建新段落和文本运行时在新的
XWPFDocument
中创建注释。将特殊位置的注释添加到现有文档中是一项非常复杂的任务。这不是一个问题可以回答的问题,因为这里有多个问题:在一个位置插入?那么:如何在文档中找到起始和结束位置?如果找到,如何在这些位置插入注释范围标记?评论一个现有的单词?然后:如何将单个单词放入自己的文本运行中,并在该文本运行之前和之后插入注释范围标记?
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 CreateWordWithComments {

//a method for creating the CommentsDocument /word/comments.xml in the *.docx ZIP archive  
 private static MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document) throws Exception {
  OPCPackage oPCPackage = document.getPackage();
  PackagePartName partName = PackagingURIHelper.createPartName("/word/comments.xml");
  PackagePart part = oPCPackage.createPart(partName, "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
  MyXWPFCommentsDocument myXWPFCommentsDocument = new MyXWPFCommentsDocument(part);

  String rId = "rId" + (document.getRelationParts().size()+1);
  document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);

  return myXWPFCommentsDocument;
 }

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

  XWPFDocument document = new XWPFDocument();

  MyXWPFCommentsDocument myXWPFCommentsDocument = createCommentsDocument(document);

  CTComments comments = myXWPFCommentsDocument.getComments();
  CTComment ctComment;
  XWPFParagraph paragraph;
  XWPFRun run;

//first comment
  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); //comment range start is set before text run
  run = paragraph.createRun();
  run.setText("Paragraph with the first comment.");
  paragraph.getCTP().addNewCommentRangeEnd().setId(cId); //comment range end is set after text run

  paragraph.getCTP().addNewR().addNewCommentReference().setId(cId); 

//paragraph without comment
  paragraph = document.createParagraph();
  run = paragraph.createRun();
  run.setText("Paragraph without comment.");

//second comment
  cId = cId.add(BigInteger.ONE);

  ctComment = comments.addNewComment();
  ctComment.setAuthor("Axel Ríchter");
  ctComment.setInitials("AR");
  ctComment.setDate(new GregorianCalendar(Locale.US));
  ctComment.addNewP().addNewR().addNewT().setStringValue("The second comment. Comments the word \"second\".");
  ctComment.setId(cId);

  paragraph = document.createParagraph();
  run = paragraph.createRun();
  run.setText("Paragraph with the ");

  paragraph.getCTP().addNewCommentRangeStart().setId(cId); //comment range start is set before text run
  run = paragraph.createRun();
  run.setText("second");
  paragraph.getCTP().addNewCommentRangeEnd().setId(cId); //comment range end is set after text run

  run = paragraph.createRun();
  run.setText(" comment.");

  paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);

//write document
  FileOutputStream out = new FileOutputStream("CreateWordWithComments.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);
   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();
  }

 }

}