package com.aspose.words.examples.programming_documents.joining_appending;
import com.aspose.words.*;
import com.aspose.words.examples.Utils;
import java.text.MessageFormat;
public class ConvertNumPageFields {
public static void main(String[] args) throws Exception {
// The path to the documents directory.
String dataDir = Utils.getDataDir(ConvertNumPageFields.class);
Document dstDoc = new Document(dataDir + "TestFile.Destination.doc");
Document srcDoc = new Document(dataDir + "TestFile.Source.doc");
// Restart the page numbering on the start of the source document.
srcDoc.getFirstSection().getPageSetup().setRestartPageNumbering(true);
srcDoc.getFirstSection().getPageSetup().setPageStartingNumber(1);
// Append the source document to the end of the destination document.
dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);
// After joining the documents the NUMPAGE fields will now display the total number of pages which
// is undesired behaviour. Call this method to fix them by replacing them with PAGEREF fields.
convertNumPageFieldsToPageRef(dstDoc);
// This needs to be called in order to update the new fields with page numbers.
dstDoc.updatePageLayout();
dstDoc.save(dataDir + "output.doc");
}
/**
* Replaces all NUMPAGES fields in the document with PAGEREF fields. The replacement field displays the total number
* of pages in the sub document instead of the total pages in the document.
*
* @param doc The combined document to process.
*/
public static void convertNumPageFieldsToPageRef(Document doc) throws Exception {
// This is the prefix for each bookmark which signals where page numbering restarts.
// The underscore "_" at the start inserts this bookmark as hidden in MS Word.
final String BOOKMARK_PREFIX = "_SubDocumentEnd";
// Field name of the NUMPAGES field.
final String NUM_PAGES_FIELD_NAME = "NUMPAGES";
// Field name of the PAGEREF field.
final String PAGE_REF_FIELD_NAME = "PAGEREF";
// Create a new DocumentBuilder which is used to insert the bookmarks and replacement fields.
DocumentBuilder builder = new DocumentBuilder(doc);
// Defines the number of page restarts that have been encountered and therefore the number of "sub" documents
// found within this document.
int subDocumentCount = 0;
// Iterate through all sections in the document.
for (Section section : doc.getSections()) {
// This section has it's page numbering restarted so we will treat this as the start of a sub document.
// Any PAGENUM fields in this inner document must be converted to special PAGEREF fields to correct numbering.
if (section.getPageSetup().getRestartPageNumbering()) {
// Don't do anything if this is the first section in the document. This part of the code will insert the bookmark marking
// the end of the previous sub document so therefore it is not applicable for first section in the document.
if (!section.equals(doc.getFirstSection())) {
// Get the previous section and the last node within the body of that section.
Section prevSection = (Section) section.getPreviousSibling();
Node lastNode = prevSection.getBody().getLastChild();
// Use the DocumentBuilder to move to this node and insert the bookmark there.
// This bookmark represents the end of the sub document.
builder.moveTo(lastNode);
builder.startBookmark(BOOKMARK_PREFIX + subDocumentCount);
builder.endBookmark(BOOKMARK_PREFIX + subDocumentCount);
// Increase the subdocument count to insert the correct bookmarks.
subDocumentCount++;
}
}
// The last section simply needs the ending bookmark to signal that it is the end of the current sub document.
if (section.equals(doc.getLastSection())) {
// Insert the bookmark at the end of the body of the last section.
// Don't increase the count this time as we are just marking the end of the document.
Node lastNode = doc.getLastSection().getBody().getLastChild();
builder.moveTo(lastNode);
builder.startBookmark(BOOKMARK_PREFIX + subDocumentCount);
builder.endBookmark(BOOKMARK_PREFIX + subDocumentCount);
}
// Iterate through each NUMPAGES field in the section and replace the field with a PAGEREF field referring to the bookmark of the current subdocument
// This bookmark is positioned at the end of the sub document but does not exist yet. It is inserted when a section with restart page numbering or the last
// section is encountered.
for (Node node : section.getChildNodes(NodeType.FIELD_START, true).toArray()) {
FieldStart fieldStart = (FieldStart) node;
if (fieldStart.getFieldType() == FieldType.FIELD_NUM_PAGES) {
// Get the field code.
String fieldCode = getFieldCode(fieldStart);
// Since the NUMPAGES field does not take any additional parameters we can assume the remaining part of the field
// code after the fieldname are the switches. We will use these to help recreate the NUMPAGES field as a PAGEREF field.
String fieldSwitches = fieldCode.replace(NUM_PAGES_FIELD_NAME, "").trim();
// Inserting the new field directly at the FieldStart node of the original field will cause the new field to
// not pick up the formatting of the original field. To counter this insert the field just before the original field
Node previousNode = fieldStart.getPreviousSibling();
// If a previous run cannot be found then we are forced to use the FieldStart node.
if (previousNode == null)
previousNode = fieldStart;
// Insert a PAGEREF field at the same position as the field.
builder.moveTo(previousNode);
// This will insert a new field with a code like " PAGEREF _SubDocumentEnd0 *\MERGEFORMAT ".
Field newField = builder.insertField(MessageFormat.format(" {0} {1}{2} {3} ", PAGE_REF_FIELD_NAME, BOOKMARK_PREFIX, subDocumentCount, fieldSwitches));
// The field will be inserted before the referenced node. Move the node before the field instead.
previousNode.getParentNode().insertBefore(previousNode, newField.getStart());
// Remove the original NUMPAGES field from the document.
removeField(fieldStart);
}
}
}
}
/**
* Retrieves the field code from a field.
*
* @param fieldStart The field start of the field which to gather the field code from.
*/
private static String getFieldCode(FieldStart fieldStart) throws Exception {
StringBuilder builder = new StringBuilder();
for (Node node = fieldStart; node != null && node.getNodeType() != NodeType.FIELD_SEPARATOR &&
node.getNodeType() != NodeType.FIELD_END; node = node.nextPreOrder(node.getDocument())) {
// Use text only of Run nodes to avoid duplication.
if (node.getNodeType() == NodeType.RUN)
builder.append(node.getText());
}
return builder.toString();
}
/**
* Removes the Field from the document.
*
* @param fieldStart The field start node of the field to remove.
*/
private static void removeField(FieldStart fieldStart) throws Exception {
Node currentNode = fieldStart;
boolean isRemoving = true;
while (currentNode != null && isRemoving) {
if (currentNode.getNodeType() == NodeType.FIELD_END)
isRemoving = false;
Node nextNode = currentNode.nextPreOrder(currentNode.getDocument());
currentNode.remove();
currentNode = nextNode;
}
}
}