There is often a need to insert one document into another. For example insert a document at a bookmark, merge field or at a custom text marker. At the moment, there is no single method in Aspose.Words that allows doing this in one line of code.
However, a document in Aspose.Words is represented by a tree of nodes, the object model is rich and the issue of combining documents is just a matter of moving nodes between the document trees. This article shows how to implement a method for inserting one document into another and use it in a variety of scenarios.
Insert a Document at Any Location
To insert content of one document to another at an arbitrary location the following simple InsertDocument method can be used. This technique will be referred to by other scenarios described below.
Example InsertDocumentMain
This is a method that inserts contents of one document at a specified location in another document.
[C#]
/// <summary>
/// Inserts content of the external document after the specified node.
/// Section breaks and section formatting of the inserted document are ignored.
/// </summary>
/// <param name="insertAfterNode">Node in the destination document after which the content
/// should be inserted. This node should be a block level node (paragraph or table).</param>
/// <param name="srcDoc">The document to insert.</param>
public void InsertDocument(Node insertAfterNode, Document srcDoc)
{
// Make sure that the node is either a pargraph or table.
if ((!insertAfterNode.NodeType.Equals(NodeType.Paragraph)) &
(!insertAfterNode.NodeType.Equals(NodeType.Table)))
throw new ArgumentException("The destination node should be either a paragraph or table.");
// We will be inserting into the parent of the destination paragraph.
CompositeNode dstStory = insertAfterNode.ParentNode;
// This object will be translating styles and lists during the import.
NodeImporter importer = new NodeImporter(srcDoc, insertAfterNode.Document, ImportFormatMode.KeepSourceFormatting);
// Loop through all sections in the source document.
foreach (Section srcSection in srcDoc.Sections)
{
// Loop through all block level nodes (paragraphs and tables) in the body of the section.
foreach (Node srcNode in srcSection.Body)
{
// Let's skip the node if it is a last empty paragarph in a section.
if (srcNode.NodeType.Equals(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, insertAfterNode);
insertAfterNode = newNode;
}
}
}
[Visual Basic]
''' <summary>
''' Inserts content of the external document after the specified node.
''' Section breaks and section formatting of the inserted document are ignored.
''' </summary>
''' <param name="insertAfterNode">Node in the destination document after which the content
''' should be inserted. This node should be a block level node (paragraph or table).</param>
''' <param name="srcDoc">The document to insert.</param>
Public Sub InsertDocument(ByVal insertAfterNode As Node, ByVal srcDoc As Document)
' Make sure that the node is either a pargraph or table.
If ((Not insertAfterNode.NodeType.Equals(NodeType.Paragraph))) And ((Not insertAfterNode.NodeType.Equals(NodeType.Table))) Then
Throw New ArgumentException("The destination node should be either a paragraph or table.")
End If
' We will be inserting into the parent of the destination paragraph.
Dim dstStory As CompositeNode = insertAfterNode.ParentNode
' This object will be translating styles and lists during the import.
Dim importer As NodeImporter = New NodeImporter(srcDoc, insertAfterNode.Document, ImportFormatMode.KeepSourceFormatting)
' Loop through all sections in the source document.
For Each srcSection As Section In srcDoc.Sections
' Loop through all block level nodes (paragraphs and tables) in the body of the section.
For Each srcNode As Node In srcSection.Body
' Let's skip the node if it is a last empty paragarph in a section.
If srcNode.NodeType.Equals(NodeType.Paragraph) Then
Dim para As Paragraph = CType(srcNode, Paragraph)
If para.IsEndOfSection AndAlso (Not para.HasChildNodes) Then
GoTo Continue1
End If
End If
' This creates a clone of the node, suitable for insertion into the destination document.
Dim newNode As Node = importer.ImportNode(srcNode, True)
' Insert new node after the reference node.
dstStory.InsertAfter(newNode, insertAfterNode)
insertAfterNode = newNode
Continue1:
Next srcNode
Next srcSection
End Sub
[Java]
/// <summary>
/// Inserts content of the external document after the specified node.
/// Section breaks and section formatting of the inserted document are ignored.
/// </summary>
/// <param name="insertAfterNode">Node in the destination document after which the content
/// should be inserted. This node should be a block level node (paragraph or table).</param>
/// <param name="srcDoc">The document to insert.</param>
public void InsertDocument(Node insertAfterNode, Document srcDoc) throws Exception
{
// Make sure that the node is either a pargraph or table.
if ((insertAfterNode.getNodeType() != NodeType.PARAGRAPH) &
(insertAfterNode.getNodeType() != NodeType.TABLE))
throw new Exception("The destination node should be either a paragraph or table.");
// We will be inserting into the parent of the destination paragraph.
CompositeNode dstStory = insertAfterNode.getParentNode();
// This object will be translating styles and lists during the import.
NodeImporter importer = new NodeImporter(srcDoc, insertAfterNode.getDocument(), ImportFormatMode.KEEP_SOURCE_FORMATTING);
// Loop through all sections in the source document.
for (Node sectionNode : srcDoc.getSections())
{
Section srcSection = (Section)sectionNode;
// Loop through all block level nodes (paragraphs and tables) in the body of the section.
for (Node srcNode : srcSection.getBody())
{
// Let's skip the node if it is a last empty paragarph 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, insertAfterNode);
insertAfterNode = newNode;
}
}
}
Insert a Document at a Bookmark
Use the InsertDocument method shown above to insert documents in bookmarked places of the main template.
To do this, just create a bookmarked paragraph where you want the document to be inserted. This bookmark should not enclose multiple paragraphs or text that you want to appear in the resulting document after the generation. Just set an empty paragraph and bookmark it. You can even put a small description of the inserted content inside this paragraph.
Example InsertDocumentAtBookmark
Invokes the InsertDocument method shown above to insert a document at a bookmark.
[C#]
Document mainDoc = new Document(MyDir + "InsertDocument1.doc");
Document subDoc = new Document(MyDir + "InsertDocument2.doc");
Bookmark bookmark = mainDoc.Range.Bookmarks["insertionPlace"];
InsertDocument(bookmark.BookmarkStart.ParentNode, subDoc);
mainDoc.Save(MyDir + "InsertDocumentAtBookmark Out.doc");
[Visual Basic]
Dim mainDoc As Document = New Document(MyDir & "InsertDocument1.doc")
Dim subDoc As Document = New Document(MyDir & "InsertDocument2.doc")
Dim bookmark As Bookmark = mainDoc.Range.Bookmarks("insertionPlace")
InsertDocument(bookmark.BookmarkStart.ParentNode, subDoc)
mainDoc.Save(MyDir & "InsertDocumentAtBookmark Out.doc")
[Java]
Document mainDoc = new Document(getMyDir() + "InsertDocument1.doc");
Document subDoc = new Document(getMyDir() + "InsertDocument2.doc");
Bookmark bookmark = mainDoc.getRange().getBookmarks().get("insertionPlace");
InsertDocument(bookmark.getBookmarkStart().getParentNode(), subDoc);
mainDoc.save(getMyDir() + "InsertDocumentAtBookmark Out.doc");
Insert a Document During Mail Merge
This example relies on the InsertDocument method shown at the beginning of the article to insert a document into a merge field during mail merge execution.
Example InsertDocumentAtMailMerge
Demonstrates how to use the InsertDocument method sown above to insert a document into a merge field during mail merge.
[C#]
public void InsertDocumentAtMailMerge()
{
// Open the main document.
Document mainDoc = new Document(MyDir + "InsertDocument1.doc");
// Add a hadler to MergeField event
mainDoc.MailMerge.MergeField += new MergeFieldEventHandler(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.MailMerge.Execute(
new string[] { "Document_1" },
new string[] { MyDir + "InsertDocument2.doc" });
mainDoc.Save(MyDir + "InsertDocumentAtMailMerge Out.doc");
}
/// <summary>
/// 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.
/// </summary>
public void InsertDocumentAtMailMergeHandler(object sender, MergeFieldEventArgs e)
{
if (e.DocumentFieldName.Equals("Document_1"))
{
// Use document builder to navigate to the merge field with the specified name.
DocumentBuilder builder = new DocumentBuilder(e.Document);
builder.MoveToMergeField(e.DocumentFieldName);
// The name of the document to load and insert is stored in the field value.
Document subDoc = new Document((string)e.FieldValue);
// Insert the document.
InsertDocument(builder.CurrentParagraph, subDoc);
// The paragraph that contained the merge field might be empty now and you probably want to delete it.
if (!builder.CurrentParagraph.HasChildNodes)
builder.CurrentParagraph.Remove();
// Indicate to the mail merge engine that we have inserted what we wanted.
e.Text = null;
}
}
[Visual Basic]
Public Sub InsertDocumentAtMailMerge()
' Open the main document.
Dim mainDoc As Document = New Document(MyDir & "InsertDocument1.doc")
' Add a hadler to MergeField event
AddHandler mainDoc.MailMerge.MergeField, AddressOf InsertDocumentAtMailMergeHandler
' The main document has a merge field in it called "Document_1".
' The corresponding data for this field