XPages - docx4j - replacing a bookmark with text

我的未来我决定 提交于 2019-12-13 04:01:32

问题


I'm using docx4j in an XPages application to create Word documents containing content from an XPage. The Word document (in .docx format) is created based on a template (in .dotx format). One bookmark from my .dotx template is as follows:

<w:p>
<w:bookmarkStart w:name="Fachkompetenz" w:id="0"/>
<w:bookmarkEnd w:id="0"/>
</w:p>

Using the function

private static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {

        List<Object> result = new ArrayList<Object>();
        if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue();

        if (obj.getClass().equals(toSearch))
            result.add(obj); 
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }

        return result; 
    }

I can get the p object by calling

List<Object> texts = getAllElementFromObject(template.getMainDocumentPart(), P.class);

or the CTBookmark object calling

List<Object> texts = getAllElementFromObject(template.getMainDocumentPart(), P.class);

However, once I have these objects I don't know how to add text (XPage content) to replace the bookmark. I've read as much as I can find on the internet on this topic but can't find any way of doing this. Does anybody have any suggestion?


回答1:


If you can, you might want to reconsider your approach.

Since bookmarks are "point" tags, it is not so easy to replace their content. For example, the opening tag could be in a top level paragraph, and the closing one in a table cell!

You may find content control data binding works better.

That said, assuming your bookmark start and end is in a single p (as per your example xml), you could try the following approach:

  1. find the bookmark start element
  2. use getParent to access the list containing it
  3. iterate through the list to find the end element
  4. replace the content between the 2 list entries

At step 4, you'll be wanting to insert new run (w:r) objects containing text (w:t). You can upload a sample docx to the docx4j webapp to generate code for that.

BookmarksReplaceWithText.java may help.




回答2:


I managed to solve this problem by using the below function. It may need refactoring in future but it works for now:

private void replaceParagraph(String placeholder, String textToAdd, WordprocessingMLPackage template) {


        List<Object> paragraphs = getAllElementFromObject(template.getMainDocumentPart(), P.class);

        for (Object p : paragraphs) {  
            RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
            new TraversalUtil(p, rt);

            for (CTBookmark content : rt.getStarts()) {  

                if (content.getName().equals(placeholder)) {  

                    List<Object> theList = null;
                    if (content.getParent() instanceof P) {
                    theList = ((ContentAccessor)(content.getParent())).getContent();
                    } else {
                    continue; 
                    }

                    if (textToAdd == ""){ 

                        int index = theList.indexOf(content);
                        Object removed = theList.remove(index);
                    } else {
                    org.docx4j.wml.R run = factory.createR();
                    org.docx4j.wml.Text t2 = factory.createText();
                    run.getContent().add(t2);   
                    t2.setValue(textToAdd);
                    theList.add(0, run); 
                    break;
                    } 
                } 
            }  

        } 

    }

Jason, thanks for your help.



来源:https://stackoverflow.com/questions/24998463/xpages-docx4j-replacing-a-bookmark-with-text

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!