This question was raised a few times, but I don't think we've given a code sample before.
Basically, it is all possible. However, there are no high-level functions in Aspose.Words for this. The problem with copying bookmark (content and formatting) is that in Aspose.Words the document is represented by a tree. Bookmark start is a node in the tree and a bookmark end is another node in a tree. They are like "marker" nodes. All nodes in between constitute content of the bookmark.
The problem begins when you think that there actually can be many scenarios where bookmarks can start and end and what "fragment" of a tree needs to be copied. Say, if bookmark starts and ends within the same paragraph, then only "inline" nodes should be copied. When copying, such nodes should be inserted at the inline level in the destination.
A bookmark can start and end in different paragraphs, but in the same section. Copying such a bookmark will involve at least copying all paragraphs and tables that are between the start and end of the bookmark, but might also involve partial copying of the paragraphs that contain start and end nodes of the bookmark. This list of scenarios can go on.
One day, Aspose.Words will have nice and easy methods to do all of that and more. But in the meantime you need to carry on and this sample gives you a solution at least for some scenarios and also gives you the general direction where to look. With just a bit of coding you can do anything with a document in Aspose.Words. You work with XmlDocument and XmlElement most likely, so it should be no problem for you to work with all the classes in Aspose.Words since they represent the similar DOM tree concept.
---------
In this example we have a document with a bookmark. The bookmark encompasses a range of paragraphs and tables. The bookmark starts and ends within the same section of the document. This screenshot shows highlighted the content of the bookmark in Microsoft Word:
The task that this sample achieves is simply taking the content of this bookmark and inserting it into another document. In this example the destination document is empty and the content of the bookmark is appended to the end of the last section of the document. The picture below shows the resulting document (the content of the bookmark was copied twice):
The code to do this might appear long, but it is very simple. It is long due to the comments:
using System;
using
System.IO;
using
System.Reflection;
using
Aspose.Words;
namespace
Project
{
/// <summary>
/// Shows how to copy bookmarked text from one document to another.
///
/// Does not cover all cases possible (bookmark can start/end in various places of a document
/// making copying scenario more complex).
///
/// Supported scenarios at the moment are:
///
/// 1. Bookmark start and end are in the same section of the document, but in different paragraphs.
/// Complete paragraphs are copied.
///
/// </summary>
class Demo
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Demo demo = new Demo();
demo.Execute();
}
private string TemplateDir
{
get
{
// The templates are stored in the directory one level up from the bin directory.
return Path.GetDirectoryName(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
}
}
private void Execute()
{
// Load the source document.
Document srcDoc = new Document(Path.Combine(TemplateDir, "Template.doc"));
// This is the bookmark whose content we want to copy.
Bookmark srcBookmark = srcDoc.Range.Bookmarks["ntf010145060"];
// We will be adding to this document.
Document dstDoc = new Document();
// Let's say we will be appending to the end of the body of the last section.
CompositeNode dstNode = dstDoc.LastSection.Body;
// It is a good idea to use this import context object because multiple nodes are being imported.
// If you import multiple times without a single context, it will result in many styles created.
NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KeepSourceFormatting);
// Do it once.
AppendBookmarkedText(importer, srcBookmark, dstNode);
// Do it one more time for fun.
AppendBookmarkedText(importer, srcBookmark, dstNode);
// Save the finished document.
dstDoc.Save(Path.Combine(TemplateDir, "Template Out.doc"));
}
/// <summary>
/// Copies content of the bookmark and adds it to the end of the specified node.
/// The destination node can be in a different document.
/// </summary>
/// <param name="importer">Maintains the import context </param>
/// <param name="srcBookmark"></param>
/// <param name="dstNode">Must be a node that can contain paragraphs (such as a Story).</param>
private void AppendBookmarkedText(NodeImporter importer, Bookmark srcBookmark, CompositeNode dstNode)
{
// This is the paragraph that contains the beginning of the bookmark.
Paragraph startPara = srcBookmark.BookmarkStart.ParentNode as Paragraph;
// This is the paragraph that contains the end of the bookmark.
Paragraph endPara = srcBookmark.BookmarkEnd.ParentNode as Paragraph;
if ((startPara == null) || (endPara == null))
throw new InvalidOperationException("Parent of the bookmark start or end is not a paragraph, cannot handle this scenario yet.");
// Limit ourselves to a reasonably simple scenario.
if (startPara.ParentNode != endPara.ParentNode)
throw new InvalidOperationException("Start and end paragraphs have different parents, cannot handle this scenario yet.");
// We want to copy all paragraphs from the start paragraph up to (and including) the end paragraph,
// therefore the node at which we stop is one after the end paragraph.
Node endNode = endPara.NextSibling;
// This is the loop to go through all paragraph-level nodes in the bookmark.
for (Node curNode = startPara; curNode != endNode; curNode = curNode.NextSibling)
{
// This creates a copy of the current node and imports it (makes it valid) in the context
// of the destination document. Importing means adjusting styles and list identifiers correctly.
Node newNode = importer.ImportNode(curNode, true);
// Now we simply append the new node to the destination.
dstNode.AppendChild(newNode);
}
}
}
}
----
Finally, a complete project is attached that you can download, compile and run.
Roman Korchagin
Aspose.Words Team Leader
Aspose Auckland Team