Insert and Append Documents

Sometimes it is required to combine several documents into one. You can do this manually or you can use Aspose.Words insert or append feature.

The insert operation allows you to insert the content of previously created documents into a new or existing one.

In turn, the append feature allows you to add a document only at the end of another document.

This article explains how to insert or append a document to another one in different ways and describes the common properties that you can apply while inserting or appending documents.

Insert a Document

As mentioned above, in Aspose.Words a document is represented as a tree of nodes, and the operation of inserting one document into another is copying nodes from the first document tree to the second one.

You can insert documents in a variety of locations in different ways. For example, you can insert a document through a replace operation, a merge field during a merge operation, or via a bookmark.

You can also use the InsertDocument method, which is similar to inserting a document in Microsoft Word, to insert a whole document at the current cursor position without any previous importing.

The following subsections describe the options during which you can insert one document into another.

Insert a Document During Find and Replace Operation

You can insert documents while performing find and replace operations. For example, a document can contain paragraphs with the text [INTRODUCTION] and [CONCLUSION]. But in the final document, you need to replace those paragraphs with the content obtained from another external document. To achieve that, you will need to create a handler for the replace event.

The following code example shows how to create a handler for the replacing event to use it later in the inserting process:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
private static class InsertDocumentAtReplaceHandler implements IReplacingCallback {
public int replacing(ReplacingArgs e) throws Exception {
Document subDoc = new Document(dataDir + "InsertDocument2.doc");
// Insert a document after the paragraph, containing the match text.
Paragraph para = (Paragraph) e.getMatchNode().getParentNode();
insertDocument(para, subDoc);
// Remove the paragraph with the match text.
para.remove();
return ReplaceAction.SKIP;
}
}

The following code example shows how insert content of one document into another during a find and replace operation:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document mainDoc = new Document(dataDir + "InsertDocument1.doc");
// Set find and replace options.
FindReplaceOptions options = new FindReplaceOptions();
options.setDirection(FindReplaceDirection.BACKWARD);
options.setReplacingCallback(new InsertDocumentAtReplaceHandler());
mainDoc.getRange().replace(Pattern.compile("\\[MY_DOCUMENT\\]"), "", options);
mainDoc.save(dataDir + "InsertDocument.InsertDocumentAtReplace.docx");

Insert a Document During Mail Merge Operation

You can insert a document into a merge field during a mail merge operation. For example, a mail merge template can contain a merge field such as [Summary]. But in the final document, you need to insert content obtained from another external document into this merge field. To achieve that, you will need to create a handler for the merge event.

The following code example shows how to create a handler for the merging event to use it later in the inserting process:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
private static class InsertDocumentAtMailMergeHandler implements IFieldMergingCallback {
/**
* This handler makes special processing for the "Document_1" field. The
* field value contains the path to load the document. We load the
* document and insert it into the current merge field.
*/
public void fieldMerging(FieldMergingArgs e) throws Exception {
if ("Document_1".equals(e.getDocumentFieldName())) {
// Use document builder to navigate to the merge field with the specified name.
DocumentBuilder builder = new DocumentBuilder(e.getDocument());
builder.moveToMergeField(e.getDocumentFieldName());
// The name of the document to load and insert is stored in the field value.
Document subDoc = new Document((String) e.getFieldValue());
// Insert the document.
insertDocument(builder.getCurrentParagraph(), subDoc);
// The paragraph that contained the merge field might be empty now and you probably want to delete it.
if (!builder.getCurrentParagraph().hasChildNodes())
builder.getCurrentParagraph().remove();
// Indicate to the mail merge engine that we have inserted what we wanted.
e.setText(null);
}
}
public void imageFieldMerging(ImageFieldMergingArgs args) throws Exception {
// Do nothing.
}
}

The following code example shows how to insert a document into the merge field using the created handler:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
// Open the main document.
Document mainDoc = new Document(dataDir + "InsertDocument1.doc");
// Add a handler to MergeField event
mainDoc.getMailMerge().setFieldMergingCallback(new InsertDocumentAtMailMergeHandler());
// The main document has a merge field in it called "Document_1".
// The corresponding data for this field contains fully qualified path to the document
// that should be inserted to this field.
mainDoc.getMailMerge().execute(new String[]{"Document_1"}, new String[]{dataDir + "InsertDocument2.doc"});
mainDoc.save(dataDir + "InsertDocument.InsertAtMailMerge.docx");

Insert a Document at Bookmark

You can import a text file into a document and insert it right after a bookmark that you have defined in the document. To do this, create a bookmarked paragraph where you want the document to be inserted.

The following coding example shows how to insert the contents of one document to a bookmark in another document:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document mainDoc = new Document(dataDir + "InsertDocument1.doc");
Document subDoc = new Document(dataDir + "InsertDocument2.doc");
Bookmark bookmark = mainDoc.getRange().getBookmarks().get("insertionPlace");
insertDocument(bookmark.getBookmarkStart().getParentNode(), subDoc);
mainDoc.save(dataDir + "InsertDocumentAtBookmark_out.doc");

Append a Document

You may have a use case where you need to include additional pages from a document to the end of an existing document. To do this, you just need to call the AppendDocument method to add a document to the end of another one.

The following code example shows how to append a document to the end of another document:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
// The document that the content will be appended to.
Document dstDoc = new Document();
dstDoc.getFirstSection().getBody().appendParagraph("Destination document text. ");
// The document to append.
Document srcDoc = new Document();
srcDoc.getFirstSection().getBody().appendParagraph("Source document text. ");
// Append the source document to the destination document.
// Pass format mode to retain the original formatting of the source document when importing it.
dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);
// Save the document.
dstDoc.save(dataDir + "Document.AppendDocument.docx");

Import and Insert Nodes Manually

Aspose.Words allows you to insert and append documents automatically without any previous importing requirements. However, if you need to insert or append a specific node of your document, such as a section or a paragraph, then first you need to import this node manually.

When you need to insert or append one section or paragraph to another, you essentially need to import the nodes of the first document node tree into the second one using the ImportNode method. After importing your nodes, you need to use the InsertAfter method to insert a new node after/before the reference node. This allows you to customize the inserting process by importing nodes from a document and inserting it at given positions.

You can also use the AppendChild method to add a new specified node to the end of the list of child nodes, for example, if you want to append content at the paragraph level instead of at the section level.

The following code example shows how to insert document content into another document using the InsertDocument method:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
// Upload a Document.
Document doc = new Document(dataDir + "Document.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
builder.moveToDocumentEnd();
builder.insertBreak(BreakType.PAGE_BREAK);
// Insert a document using the InsertDocument method.
Document docToInsert = new Document(dataDir + "Formatted elements.docx");
builder.insertDocument(docToInsert, ImportFormatMode.KEEP_SOURCE_FORMATTING);
builder.getDocument().save(dataDir + "DocumentBuilder.InsertDocument.docx");

The following code example shows how to manually import nodes and insert them after a specific node using the InsertAfter method:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
/**
* Inserts content of the external document after the specified node.
* Section breaks and section formatting of the inserted document are
* ignored.
*
* @param insertionDestination Node in the destination document after which the content
* should be inserted. This node should be a block level node
* (paragraph or table).
* @param docToInsert The document to insert.
*/
public static void insertDocument(Node insertionDestination, Document docToInsert)
{
// Make sure that the node is either a paragraph or table.
if (((insertionDestination.getNodeType()) == (NodeType.PARAGRAPH)) || ((insertionDestination.getNodeType()) == (NodeType.TABLE)))
{
// We will be inserting into the parent of the destination paragraph.
CompositeNode dstStory = insertionDestination.getParentNode();
// This object will be translating styles and lists during the import.
NodeImporter importer = new NodeImporter(docToInsert, insertionDestination.getDocument(), ImportFormatMode.KEEP_SOURCE_FORMATTING);
// Loop through all block level nodes in the body of the section
for (Section srcSection : docToInsert.getSections().toArray())
for (Node srcNode : srcSection.getBody())
{
// Let's skip the node if it is a last empty paragraph in a section
if (((srcNode.getNodeType()) == (NodeType.PARAGRAPH)))
{
Paragraph para = (Paragraph)srcNode;
if (para.isEndOfSection() && !para.hasChildNodes())
continue;
}
// This creates a clone of the node, suitable for insertion into the destination document.
Node newNode = importer.importNode(srcNode, true);
// Insert new node after the reference node.
dstStory.insertAfter(newNode, insertionDestination);
insertionDestination = newNode;
}
}
else
{
throw new IllegalArgumentException("The destination node should be either a paragraph or table.");
}
}

Content is imported into the destination document section by section, which means that settings, such as page setup and headers or footers, are preserved during import. It is also useful to note that you can define formatting settings when you insert or append a document to specify how two documents are joined together.

Common Properties for Insert and Append Documents

Both InsertDocument and AppendDocument methods accept ImportFormatMode and ImportFormatOptions as input parameters. The ImportFormatMode allows you to control how document formatting is merged when you import content from one document into another by selecting different format modes such as UseDestinationStyles, KeepSourceFormatting, and KeepDifferentStyles. The ImportFormatOptions allows you to select different import options such as IgnoreHeaderFooter, IgnoreTextBoxes, KeepSourceNumbering, MergePastedLists, and SmartStyleBehavior.

Aspose.Words allows you to adjust the visualization of a resulting document when two documents are added together in an insert or append operation by using the Section and PageSetup properties. The PageSetup property contains all the attributes of a section such as SectionStart, RestartPageNumbering, PageStartingNumber, Orientation, and others. The most common use case is to set the SectionStart property to define if the added content will appear on the same page or split into a new one.

The following code example shows how to append one document to another while keeping the content from splitting across two pages:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
// The path to the documents directory.
String dataDir = Utils.getDataDir(DifferentPageSetup.class);
String fileName = "TestFile.DestinationList.doc";
Document dstDoc = new Document(dataDir + fileName);
Document srcDoc = new Document(dataDir + "TestFile.Source.doc");
// Set the source document to appear straight after the destination document's content.
srcDoc.getFirstSection().getPageSetup().setSectionStart(SectionStart.CONTINUOUS);
// Restart the page numbering on the start of the source document.
srcDoc.getFirstSection().getPageSetup().setRestartPageNumbering(true);
srcDoc.getFirstSection().getPageSetup().setPageStartingNumber(1);
// To ensure this does not happen when the source document has different page setup settings make sure the Settings are
// identical between the last section of the destination document. If there are further continuous sections tha
// follow on in the source document then this will need to be Repeated for those sections as well.
srcDoc.getFirstSection().getPageSetup().setPageWidth(dstDoc.getLastSection().getPageSetup().getPageWidth());
srcDoc.getFirstSection().getPageSetup().setPageHeight(dstDoc.getLastSection().getPageSetup().getPageHeight());
srcDoc.getFirstSection().getPageSetup().setOrientation(dstDoc.getLastSection().getPageSetup().getOrientation());
// Iterate through all sections in the source document.
for (Paragraph para : (Iterable<Paragraph>) srcDoc.getChildNodes(NodeType.PARAGRAPH, true))
{
para.getParagraphFormat().setKeepWithNext(true);
}
dstDoc.appendDocument(srcDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);
dataDir = dataDir + Utils.GetOutputFilePath(fileName);
dstDoc.save(dataDir);