插入和附加文档

有时需要将多个文档合并为一个。您可以手动执行此操作,也可以使用 Aspose.Words 插入或附加功能。

插入操作允许您将先前创建的文档的内容插入到新的或现有的文档中。

反过来,附加功能允许您仅在另一个文档的末尾添加文档。

本文介绍如何以不同的方式将一个文档插入或附加到另一个文档,并介绍在插入或附加文档时可以应用的常见属性。

插入文档

如上所述,在 Aspose.Words 中,文档被表示为节点树,将一个文档插入另一个文档的操作是将节点从第一个文档树复制到第二个文档树。

您可以用不同的方式将文档插入到不同的位置。例如,您可以通过替换操作、合并操作期间的合并字段或通过书签插入文档。

您还可以使用InsertDocumentInsertDocumentInline方法,类似于在Microsoft Word中插入文档,在当前光标位置插入整个文档,而无需先前导入。

以下代码示例演示如何使用 InsertDocument 方法插入文档:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document srcDoc = new Document(MyDir + "Document source.docx");
Document dstDoc = new Document(MyDir + "Northwind traders.docx");
DocumentBuilder builder = new DocumentBuilder(dstDoc);
builder.MoveToDocumentEnd();
builder.InsertBreak(BreakType.PageBreak);
builder.InsertDocument(srcDoc, ImportFormatMode.KeepSourceFormatting);
builder.Document.Save(ArtifactsDir + "JoinAndAppendDocuments.InsertDocument.docx");

以下代码示例演示如何使用 InsertDocumentInline 方法插入文档:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
DocumentBuilder srcDoc = new DocumentBuilder();
srcDoc.Write("[src content]");
// Create destination document.
DocumentBuilder dstDoc = new DocumentBuilder();
dstDoc.Write("Before ");
dstDoc.InsertNode(new BookmarkStart(dstDoc.Document, "src_place"));
dstDoc.InsertNode(new BookmarkEnd(dstDoc.Document, "src_place"));
dstDoc.Write(" after");
Assert.AreEqual("Before after", dstDoc.Document.GetText().TrimEnd());
// Insert source document into destination inline.
dstDoc.MoveToBookmark("src_place");
dstDoc.InsertDocumentInline(srcDoc.Document, ImportFormatMode.UseDestinationStyles, new ImportFormatOptions());
Assert.AreEqual("Before [src content] after", dstDoc.Document.GetText().TrimEnd());

以下小节介绍了可以将一个文档插入到另一个文档中的选项。

在查找和替换操作期间插入文档

您可以在执行查找和替换操作时插入文档。例如,文档可以包含带有文本 [简介] 和 [结论] 的段落。但在最终文档中,您需要将这些段落替换为从另一个外部文档获取的内容。为此,您需要为替换事件创建一个处理程序。

以下代码示例演示如何为替换事件创建处理程序,以便稍后在插入过程中使用它:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
private class InsertDocumentAtReplaceHandler : IReplacingCallback
{
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs args)
{
Document subDoc = new Document(MyDir + "Document insertion 2.docx");
// Insert a document after the paragraph, containing the match text.
Paragraph para = (Paragraph)args.MatchNode.ParentNode;
InsertDocument(para, subDoc);
// Remove the paragraph with the match text.
para.Remove();
return ReplaceAction.Skip;
}
}

以下代码示例演示如何在查找和替换操作期间将一个文档的内容插入到另一个文档中:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document mainDoc = new Document(MyDir + "Document insertion 1.docx");
FindReplaceOptions options = new FindReplaceOptions
{
Direction = FindReplaceDirection.Backward,
ReplacingCallback = new InsertDocumentAtReplaceHandler()
};
mainDoc.Range.Replace(new Regex("\\[MY_DOCUMENT\\]"), "", options);
mainDoc.Save(ArtifactsDir + "CloneAndCombineDocuments.InsertDocumentAtReplace.docx");

Mail Merge 操作期间插入文档

您可以在 Mail Merge 操作期间将文档插入合并字段。例如,mail merge 模板可以包含合并字段,例如 [Summary]。但在最终文档中,您需要将从另一个外部文档获取的内容插入到此合并字段中。为此,您需要为合并事件创建一个处理程序。

以下代码示例演示如何为合并事件创建处理程序,以便稍后在插入过程中使用它:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
private class InsertDocumentAtMailMergeHandler : 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.
void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
{
if (args.DocumentFieldName == "Document_1")
{
// Use document builder to navigate to the merge field with the specified name.
DocumentBuilder builder = new DocumentBuilder(args.Document);
builder.MoveToMergeField(args.DocumentFieldName);
// The name of the document to load and insert is stored in the field value.
Document subDoc = new Document((string)args.FieldValue);
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.
args.Text = null;
}
}
void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs args)
{
// Do nothing.
}
}

以下代码示例演示如何使用创建的处理程序将文档插入合并字段:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document mainDoc = new Document(MyDir + "Document insertion 1.docx");
mainDoc.MailMerge.FieldMergingCallback = new InsertDocumentAtMailMergeHandler();
// The main document has a merge field in it called "Document_1".
// The corresponding data for this field contains a fully qualified path to the document.
// That should be inserted to this field.
mainDoc.MailMerge.Execute(new[] { "Document_1" }, new object[] { MyDir + "Document insertion 2.docx" });
mainDoc.Save(ArtifactsDir + "CloneAndCombineDocuments.InsertDocumentAtMailMerge.doc");

在书签 {#insert-a-document-at-bookmark} 处插入文档

您可以将文本文件导入到文档中,并将其插入到文档中定义的书签后面。为此,请在要插入文档的位置创建一个带书签的段落。

以下编码示例显示如何将一个文档的内容插入到另一文档的书签中:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document mainDoc = new Document(MyDir + "Document insertion 1.docx");
Document subDoc = new Document(MyDir + "Document insertion 2.docx");
Bookmark bookmark = mainDoc.Range.Bookmarks["insertionPlace"];
InsertDocument(bookmark.BookmarkStart.ParentNode, subDoc);
mainDoc.Save(ArtifactsDir + "CloneAndCombineDocuments.InsertDocumentAtBookmark.docx");

附加文档

您可能有一个用例,需要将文档中的附加页面添加到现有文档的末尾。为此,您只需调用 AppendDocument 方法将一个文档添加到另一个文档的末尾。

以下代码示例演示如何将一个文档附加到另一个文档的末尾:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document dstDoc = new Document();
dstDoc.FirstSection.Body.AppendParagraph("Destination document text. ");
Document srcDoc = new Document();
srcDoc.FirstSection.Body.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.KeepSourceFormatting);
dstDoc.Save(ArtifactsDir + "JoinAndAppendDocuments.KeepSourceFormatting.docx");

手动导入和插入节点

Aspose.Words 允许您自动插入和附加文档,无需任何先前的导入要求。但是,如果您需要插入或附加文档的特定节点(例如节或段落),那么首先需要手动导入该节点。

当您需要将一个部分或段落插入或附加到另一个部分或段落时,本质上需要使用 ImportNode 方法将第一个文档节点树的节点导入到第二个文档节点树中。导入节点后,您需要使用 InsertAfter / InsertBefore 方法在引用节点之后/之前插入新节点。这允许您通过从文档导入节点并将其插入给定位置来自定义插入过程。

您还可以使用 AppendChild 方法将新的指定节点添加到子节点列表的末尾,例如,如果您想在段落级别而不是节级别追加内容。

以下代码示例展示了如何使用 InsertAfter 方法手动导入节点并将其插入到特定节点之后:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
/// <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="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>
/// <param name="docToInsert">The document to insert.</param>
private static void InsertDocument(Node insertionDestination, Document docToInsert)
{
if (insertionDestination.NodeType == NodeType.Paragraph || insertionDestination.NodeType == NodeType.Table)
{
CompositeNode destinationParent = insertionDestination.ParentNode;
NodeImporter importer =
new NodeImporter(docToInsert, insertionDestination.Document, ImportFormatMode.KeepSourceFormatting);
// Loop through all block-level nodes in the section's body,
// then clone and insert every node that is not the last empty paragraph of a section.
foreach (Section srcSection in docToInsert.Sections.OfType<Section>())
foreach (Node srcNode in srcSection.Body)
{
if (srcNode.NodeType == NodeType.Paragraph)
{
Paragraph para = (Paragraph)srcNode;
if (para.IsEndOfSection && !para.HasChildNodes)
continue;
}
Node newNode = importer.ImportNode(srcNode, true);
destinationParent.InsertAfter(newNode, insertionDestination);
insertionDestination = newNode;
}
}
else
{
throw new ArgumentException("The destination node should be either a paragraph or table.");
}
}

内容将逐节导入到目标文档中,这意味着在导入过程中会保留页面设置和页眉或页脚等设置。值得注意的是,您可以在插入或追加文档时定义格式设置,以指定两个文档如何连接在一起。

插入和附加文档 {#common-properties-for-insert-and-append-documents} 的常用属性

InsertDocumentAppendDocument 方法都接受 ImportFormatModeImportFormatOptions 作为输入参数。当您通过选择不同的格式模式(例如 UseDestinationStylesKeepSourceFormattingKeepDifferentStyles)将内容从一个文档导入到另一个文档时,ImportFormatMode 允许您控制文档格式的合并方式。 ImportFormatOptions 允许您选择不同的导入选项,例如 IgnoreHeaderFooterIgnoreTextBoxesKeepSourceNumberingMergePastedListsSmartStyleBehavior

当两个文档通过使用 SectionPageSetup 属性在插入或追加操作中添加在一起时,Aspose.Words 允许您调整结果文档的可视化。 PageSetup 属性包含节的所有属性,例如 SectionStartRestartPageNumberingPageStartingNumberOrientation 等。最常见的用例是设置 SectionStart 属性来定义添加的内容是出现在同一页面上还是拆分为新页面。

以下代码示例演示如何将一个文档追加到另一个文档,同时防止内容拆分为两页:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document srcDoc = new Document(MyDir + "Document source.docx");
Document dstDoc = new Document(MyDir + "Northwind traders.docx");
// Set the source document to continue straight after the end of the destination document.
srcDoc.FirstSection.PageSetup.SectionStart = SectionStart.Continuous;
// Restart the page numbering on the start of the source document.
srcDoc.FirstSection.PageSetup.RestartPageNumbering = true;
srcDoc.FirstSection.PageSetup.PageStartingNumber = 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 that follow on in the source document,
// this will need to be repeated for those sections.
srcDoc.FirstSection.PageSetup.PageWidth = dstDoc.LastSection.PageSetup.PageWidth;
srcDoc.FirstSection.PageSetup.PageHeight = dstDoc.LastSection.PageSetup.PageHeight;
srcDoc.FirstSection.PageSetup.Orientation = dstDoc.LastSection.PageSetup.Orientation;
// Iterate through all sections in the source document.
foreach (Paragraph para in srcDoc.GetChildNodes(NodeType.Paragraph, true))
{
para.ParagraphFormat.KeepWithNext = true;
}
dstDoc.AppendDocument(srcDoc, ImportFormatMode.KeepSourceFormatting);
dstDoc.Save(ArtifactsDir + "JoinAndAppendDocuments.DifferentPageSetup.docx");