Now handles bookmarks in tables and it strips out any and all text that may
be contained within the bookmark. I still do not know if this is correct
however.
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTMarkupRange;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
import java.util.List;
import java.util.Iterator;
import org.apache.xmlbeans.XmlCursor;
import org.w3c.dom.Node;
/**
* Second attempt at inserting text at a bookmark defined within a Word
document.
* Note that there is one SERIOUS limitations with the code as it stands; at
* least only one as far as I am aware: nested bookmarks.
*
* It is possible to create a document and to nest one bookmark within
another.
* Typically, a bookmark is inserted into a piece of text, that is then
selected
* and another bookmark is added to that selection. The xml markup might
look
* something like this
*
* <pre>
* <w:p w:rsidR="00945150" w:rsidRDefault="00945150">
* <w:r>
* <w:t xml:space="preserve">
* Imagine I want to insert one bookmark at the start of this
* </w:t>
* </w:r>
* <w:bookmarkStart w:id="0" w:name="OUTER"/>
* <w:r>
* <w:t xml:space="preserve">piece of text and another just
* </w:t>
* </w:r>
* <w:proofErr w:type="gramStart"/>
* <w:r>
* <w:t xml:space="preserve">here
* </w:t>
* </w:r>
* <w:bookmarkStart w:id="1" w:name="INNER"/>
* <w:bookmarkEnd w:id="1"/>
* <w:r>
* <w:t>.
* </w:t>
* </w:r>
* <w:bookmarkEnd w:id="0"/>
* <w:proofErr w:type="gramEnd"/>
* </w:p>
* </pre>
*
* In this case the codes usual behaviour - which is to remove any nodes
found
* between the bookmarkStart and bookmarkEnd nodes will simply result in the
* 'inner' or nested bookmark being removed. So, is the default behaviour
* correct? If it is, then the code needs to be amended to handle nested
* bookmarks and the decision must be made about just how to handle them..
*
* @author Mark Beardsley
* @version 0.20 10th June 2012
*/
public class DOCXTest {
private XWPFDocument document = null;
public DOCXTest() {
}
/**
* Opens a Word OOXML file.
*
* @param filename An instance of the String class that encapsulates the
* path to and name of a Word OOXML (.docx) file.
* @throws IOException Thrown if a problem occurs within the underlying
* file system.
*/
public final void openFile(String filename) throws IOException {
File file = null;
FileInputStream fis = null;
try {
// Simply open the file and store a reference into the
'document'
// local variable.
file = new File(filename);
fis = new FileInputStream(file);
this.document = new XWPFDocument(fis);
}
finally {
try {
if(fis != null) {
fis.close();
fis = null;
}
}
catch(IOException ioEx) {
// Swallow this exception. It would have occured onyl
// when releasing the file handle and should not pose
// problems to later processing.
}
}
}
/**
* Saves a Word OOXML file away under the name, and to the location,
* specified.
*
* @param filename An instance of the String class that encapsulates the
* of the file and the location into which it should be stored.
* @throws IOException Thrown if a problem occurs in the underlying
file
* system.
*/
public final void saveAs(String filename) throws IOException {
File file = null;
FileOutputStream fos = null;
try {
file = new File(filename);
fos = new FileOutputStream(file);
this.document.write(fos);
}
finally {
if(fos != null) {
fos.close();
fos = null;
}
}
}
/**
* Inserts a value at a location within the Word document specified by a
* named bookmark.
*
* @param bookmarkName An instance of the String class that encapsulates
* the name of the bookmark. Note that case is important and the
case
* of the bookmarks name within the document and that of the
value
* passed to this parameter must match.
* @param bookmarkValue An instance of the String class that
encapsulates
* the value that should be inserted into the document at the
location
* specified by the bookmark.
*/
public final void insertAtBookmark(String bookmarkName, String
bookmarkValue) {
List<XWPFTable> tableList = null;
Iterator<XWPFTable> tableIter = null;
List<XWPFTableRow> rowList = null;
Iterator<XWPFTableRow> rowIter = null;
List<XWPFTableCell> cellList = null;
Iterator<XWPFTableCell> cellIter = null;
XWPFTable table = null;
XWPFTableRow row = null;
XWPFTableCell cell = null;
// Firstly, deal with any paragraphs in the body of the document.
this.procParaList(this.document.getParagraphs(), bookmarkName,
bookmarkValue);
// Then check to see if there are any bookmarks in table cells. To
do this
// it is necessary to get at the list of paragraphs 'stored' within
the
// individual table cell, hence this code which get the tables from
the
// document, the rows from each table, the cells from each row and
the
// paragraphs from each cell.
tableList = this.document.getTables();
tableIter = tableList.iterator();
while(tableIter.hasNext()) {
table = tableIter.next();
rowList = table.getRows();
rowIter = rowList.iterator();
while(rowIter.hasNext()) {
row = rowIter.next();
cellList = row.getTableCells();
cellIter = cellList.iterator();
while(cellIter.hasNext()) {
cell = cellIter.next();
this.procParaList(cell.getParagraphs(),
bookmarkName,
bookmarkValue);
}
}
}
}
/**
* Inserts text into the document at the position indicated by a
specific
* bookmark. Note that the current implementation does not take account
* of nested bookmarks, that is bookmarks that contain other bookmarks.
Note
* also that any text contained within the bookmark itself will be
removed.
*
* @param paraList An instance of a class that implements the List
interface
* and which encapsulates references to one or more instances of
the
* XWPFParagraph class.
* @param bookmarkName An instance of the String class that encapsulates
the
* name of the bookmark that identifies the position within the
* document some text should be inserted.
* @param bookmarkValue An instance of the AString class that
encapsulates
* the text that should be inserted at the location specified by
the
* bookmark.
*/
private final void procParaList(List<XWPFParagraph> paraList,
String bookmarkName, String bookmarkValue) {
Iterator<XWPFParagraph> paraIter = null;
XWPFParagraph para = null;
List<CTBookmark> bookmarkList = null;
Iterator<CTBookmark> bookmarkIter = null;
CTBookmark bookmark = null;
XWPFRun run = null;
Node nextNode = null;
// Get an Iterator to step through the contents of the paragraph
list.
paraIter = paraList.iterator();
while(paraIter.hasNext()) {
// Get the paragraph, a llist of CTBookmark objects and an
Iterator
// to step through the list of CTBookmarks.
para = paraIter.next();
bookmarkList = para.getCTP().getBookmarkStartList();
bookmarkIter = bookmarkList.iterator();
while(bookmarkIter.hasNext()) {
// Get a Bookmark and check it's name. If the name of the
// bookmark matches the name the user has specified...
bookmark = bookmarkIter.next();
if(bookmark.getName().equals(bookmarkName)) {
// ...create the text run to insert and set it's text
// content and then insert that text into the document.
run = para.createRun();
run.setText(bookmarkValue);
// The new Run should be inserted between the
bookmarkStart
// and bookmarkEnd nodes, so find the bookmarkEnd node.
// Note that we are looking for the next sibling of the
// bookmarkStart node as it does not contain any child
nodes
// as far as I am aware.
nextNode = bookmark.getDomNode().getNextSibling();
// If the next node is not the bookmarkEnd node, then
step
// along the sibling nodes, until the bookmarkEnd node
// is found. As the code is here, it will remove
anything
// it finds between the start and end nodes. This, of
course
// comepltely sidesteps the issues surrounding
boorkamrks
// that contain other bookmarks which I understand can
happen.
while(!(nextNode.getNodeName().contains("bookmarkEnd")))
{
para.getCTP().getDomNode().removeChild(nextNode);
nextNode = bookmark.getDomNode().getNextSibling();
}
// Finally, insert the new Run node into the document
// between the bookmarkStrat and the bookmarkEnd nodes.
para.getCTP().getDomNode().insertBefore(
run.getCTR().getDomNode(),
nextNode);
}
}
}
}
public static void main(String[] args) {
try {
DOCXTest docxTest = new DOCXTest();
docxTest.openFile("C:/temp/Doc1.docx");
docxTest.insertAtBookmark("WHOLE_WORD", "This should be inserted
at the WHOLE_WORD bookmark.");
docxTest.insertAtBookmark("MARK_ONE", "..and this at the
MARK_ONE bookmark.");
docxTest.saveAs("C:/temp/Doc1 With Bookmarks Updated.docx");
}
catch(Exception ex) {
System.out.println("Caught a: " + ex.getClass().getName());
System.out.println("Message: " + ex.getMessage());
System.out.println("Stacktrace follows:.....");
ex.printStackTrace(System.out);
}
}
}
--
View this message in context:
http://apache-poi.1045710.n5.nabble.com/Replacing-the-value-of-the-bookmarks-tp5710052p5710121.html
Sent from the POI - User mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]