Introduction and Creating Tables

Tables are a common element found in word documents. They allow for large amounts of information to be organized and displayed clearly in a grid-like structure with rows and columns. They are also frequently used as a page layout tool and a better alternative for displaying tabbed data (with tab stops) as they allow much better control over the design and layout of the content. You can lay out content which is to be kept in a fixed position by using a borderless table. While you would normally have plain text in a table, you can also put other content in cells, such as images or even other tables.

A table is comprised of elements such as CellRow, and Column. These are concepts which are common to all tables in general whether they come from a Microsoft Word document or an HTML document. Tables in Aspose.Words are fully supported. You are able to freely edit, change, add and remove tables. Rendering of tables with high fidelity is also supported.

A table from any document loaded into Aspose.Words is imported as a Table node. A table can be found as a child of the main body of text, an inline story such as a comment or footnote, or within a cell as a nested table. Furthermore, tables can be nested inside other tables up to any depth.

Table node does not contain any real content - instead it is a container for other such nodes which make up the content:

  • A Table contains many Row nodes. A Table exposes all the normal members of a node which allows you to freely move, modify and remove the table in the document.
  • A Row represents a single row of a table and contains many Cell nodes. Additionally, a Row provides members which define how a row is displayed, for example, the height and alignment.
  • A Cell is what contains the true content seen in a table and is made up of Paragraph and other block-level nodes. Additionally, cells can contain further nested tables.

This relationship is best represented by inspecting the structure of a Table node in a document through the use of DocumentExplorer .

You can see in the diagram above that the document contains a table which consists of one row which in turn consists of two cells. Each of the two cells contains a paragraph which is the container of the formatted text ion a cell. In Aspose.Words all table related classes and properties are contained in the Aspose.Words.Tables namespace.

You should also notice the table is succeeded with an empty paragraph. It is a requirement for a Microsoft Word document to have at least one paragraph after a table. This is used to separate consecutive tables and without it such consecutive tables would be joined together into one. This behavior is identical in both Microsoft Word and Aspose.Words.

Create a Table

Aspose.Words provides several different methods to create new tables in a document. This article presents the full details of how to insert formatted tables using each technique as well as a comparison of each technique at the end of the article. A newly created table is given similar defaults as used in Microsoft Word:

Table Property Default in Aspose.Words
Border Style Single
Border Width 1/2 pt
Border Color Black
Left and Right Padding 5.4 pts
AutoFit Mode AutoFit to Window
Allow AutoFit True

Insert a Table

In Aspose.Words a table is normally inserted using DocumentBuilder. The following methods are used to build a table. Other methods will also be used to insert content into the table cells.

  • DocumentBuilder.StartTable
  • DocumentBuilder.InsertCell
  • DocumentBuilder.EndRow
  • DocumentBuilder.EndTable
  • DocumentBuilder.Writeln
Operation Description Table State
DocumentBuilder.StartTable Starts building a new table at the current cursor position.
The table is created empty and has no rows or cells yet.
DocumentBuilder.InsertCell Inserts a new row and cell into the table.
DocumentBuilder.Writeln Writes some text into the current cell.
DocumentBuilder.InsertCell Appends a new cell at the end of the current row.
DocumentBuilder.Writeln Writes some text into the current cell (now the second cell).
DocumentBuilder.EndRow Instructs the builder to end the current row and to begin a new row with the next call to DocumentBuilder.InsertCell.
DocumentBuilder.InsertCell Creates a new row and inserts a new cell.
DocumentBuilder.Writeln Inserts some text into the first cell of the second row.
DocumentBuilder.EndTable Called to finish off building the table. The builder cursor will now point outside the table ready to insert content after the table.

Below example shows how to create a simple table using DocumentBuilder with default formatting:

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(doc);
// We call this method to start building the table.
builder->StartTable();
builder->InsertCell();
builder->Write(u"Row 1, Cell 1 Content.");
// Build the second cell
builder->InsertCell();
builder->Write(u"Row 1, Cell 2 Content.");
// Call the following method to end the row and start a new row.
builder->EndRow();
// Build the first cell of the second row.
builder->InsertCell();
builder->Write(u"Row 2, Cell 1 Content");
// Build the second cell.
builder->InsertCell();
builder->Write(u"Row 2, Cell 2 Content.");
builder->EndRow();
// Signal that we have finished building the table.
builder->EndTable();
System::String outputPath = outputDataDir + u"InsertTableUsingDocumentBuilder.SimpleTable.doc";
// Save the document to disk.
doc->Save(outputPath);

Below example shows how to create a formatted table using DocumentBuilder:

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(doc);
System::SharedPtr<Table> table = builder->StartTable();
// Make the header row.
builder->InsertCell();
// Set the left indent for the table. Table wide formatting must be applied after
// At least one row is present in the table.
table->set_LeftIndent(20.0);
// Set height and define the height rule for the header row.
builder->get_RowFormat()->set_Height(40.0);
builder->get_RowFormat()->set_HeightRule(HeightRule::AtLeast);
// Some special features for the header row.
builder->get_CellFormat()->get_Shading()->set_BackgroundPatternColor(System::Drawing::Color::FromArgb(198, 217, 241));
builder->get_ParagraphFormat()->set_Alignment(ParagraphAlignment::Center);
builder->get_Font()->set_Size(16);
builder->get_Font()->set_Name(u"Arial");
builder->get_Font()->set_Bold(true);
builder->get_CellFormat()->set_Width(100.0);
builder->Write(u"Header Row,\n Cell 1");
// We don't need to specify the width of this cell because it's inherited from the previous cell.
builder->InsertCell();
builder->Write(u"Header Row,\n Cell 2");
builder->InsertCell();
builder->get_CellFormat()->set_Width(200.0);
builder->Write(u"Header Row,\n Cell 3");
builder->EndRow();
// Set features for the other rows and cells.
builder->get_CellFormat()->get_Shading()->set_BackgroundPatternColor(System::Drawing::Color::get_White());
builder->get_CellFormat()->set_Width(100.0);
builder->get_CellFormat()->set_VerticalAlignment(CellVerticalAlignment::Center);
// Reset height and define a different height rule for table body
builder->get_RowFormat()->set_Height(30.0);
builder->get_RowFormat()->set_HeightRule(HeightRule::Auto);
builder->InsertCell();
// Reset font formatting.
builder->get_Font()->set_Size(12);
builder->get_Font()->set_Bold(false);
// Build the other cells.
builder->Write(u"Row 1, Cell 1 Content");
builder->InsertCell();
builder->Write(u"Row 1, Cell 2 Content");
builder->InsertCell();
builder->get_CellFormat()->set_Width(200.0);
builder->Write(u"Row 1, Cell 3 Content");
builder->EndRow();
builder->InsertCell();
builder->get_CellFormat()->set_Width(100.0);
builder->Write(u"Row 2, Cell 1 Content");
builder->InsertCell();
builder->Write(u"Row 2, Cell 2 Content");
builder->InsertCell();
builder->get_CellFormat()->set_Width(200.0);
builder->Write(u"Row 2, Cell 3 Content.");
builder->EndRow();
builder->EndTable();
System::String outputPath = outputDataDir + u"InsertTableUsingDocumentBuilder.FormattedTable.doc";
// Save the document to disk.
doc->Save(outputPath);

Below example shows how to insert a nested table using DocumentBuilder:

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(doc);
// Build the outer table.
System::SharedPtr<Cell> cell = builder->InsertCell();
builder->Writeln(u"Outer Table Cell 1");
builder->InsertCell();
builder->Writeln(u"Outer Table Cell 2");
// This call is important in order to create a nested table within the first table
// Without this call the cells inserted below will be appended to the outer table.
builder->EndTable();
// Move to the first cell of the outer table.
builder->MoveTo(cell->get_FirstParagraph());
// Build the inner table.
builder->InsertCell();
builder->Writeln(u"Inner Table Cell 1");
builder->InsertCell();
builder->Writeln(u"Inner Table Cell 2");
builder->EndTable();
System::String outputPath = outputDataDir + u"InsertTableUsingDocumentBuilder.NestedTable.doc";
// Save the document to disk.
doc->Save(outputPath);

Insert a Table Directly into the Document Object Model

You can insert tables directly into the DOM at a particular node position. The same table defaults are used when using a DocumentBuilder to create a table. To build a new table from scratch without the use of DocumentBuilder, first, create a new Table node using the appropriate constructor, and then add it to the document tree.

Note that you must take into account that the table will initially be completely empty (i.e contains no child rows yet). In order to build the table, you will first need to add the appropriate child nodes.

Below example shows how to insert a table using the constructors of nodes.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
// The path to the documents directory.
System::String outputDataDir = GetOutputDataDir_WorkingWithTables();
System::SharedPtr<Document> doc = System::MakeObject<Document>();
// We start by creating the table object. Note how we must pass the document object
// To the constructor of each node. This is because every node we create must belong
// To some document.
System::SharedPtr<Table> table = System::MakeObject<Table>(doc);
// Add the table to the document.
doc->get_FirstSection()->get_Body()->AppendChild(table);
// Here we could call EnsureMinimum to create the rows and cells for us. This method is used
// To ensure that the specified node is valid, in this case a valid table should have at least one
// Row and one cell, therefore this method creates them for us.
// Instead we will handle creating the row and table ourselves. This would be the best way to do this
// If we were creating a table inside an algorthim for example.
System::SharedPtr<Row> row = System::MakeObject<Row>(doc);
row->get_RowFormat()->set_AllowBreakAcrossPages(true);
table->AppendChild(row);
// We can now apply any auto fit settings.
table->AutoFit(AutoFitBehavior::FixedColumnWidths);
// Create a cell and add it to the row
System::SharedPtr<Cell> cell = System::MakeObject<Cell>(doc);
cell->get_CellFormat()->get_Shading()->set_BackgroundPatternColor(System::Drawing::Color::get_LightBlue());
cell->get_CellFormat()->set_Width(80);
// Add a paragraph to the cell as well as a new run with some text.
cell->AppendChild(System::MakeObject<Paragraph>(doc));
cell->get_FirstParagraph()->AppendChild(System::MakeObject<Run>(doc, u"Row 1, Cell 1 Text"));
// Add the cell to the row.
row->AppendChild(cell);
// We would then repeat the process for the other cells and rows in the table.
// We can also speed things up by cloning existing cells and rows.
row->AppendChild((System::StaticCast<Node>(cell))->Clone(false));
row->get_LastCell()->AppendChild(System::MakeObject<Paragraph>(doc));
row->get_LastCell()->get_FirstParagraph()->AppendChild(System::MakeObject<Run>(doc, u"Row 1, Cell 2 Text"));
System::String outputPath = outputDataDir + u"InsertTableDirectly.doc";
// Save the document to disk.
doc->Save(outputPath);

Insert a Copy of an Existing Table

Often there are times when you have an existing table in a document and would like to add a copy of this table then apply some modifications. The easiest way to duplicate a table while retaining all formatting is to clone the table node using the Table.Clone method. Below example shows how to insert a table using the constructors of nodes. You can download the template file of this example from here.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>(inputDataDir + u"Table.SimpleTable.doc");
// Retrieve the first table in the document.
System::SharedPtr<Table> table = System::DynamicCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// Create a clone of the table.
System::SharedPtr<Table> tableClone = System::DynamicCast<Table>((System::StaticCast<Node>(table))->Clone(true));
// Insert the cloned table into the document after the original
table->get_ParentNode()->InsertAfter(tableClone, table);
// Insert an empty paragraph between the two tables or else they will be combined into one
// Upon save. This has to do with document validation.
table->get_ParentNode()->InsertAfter(System::MakeObject<Paragraph>(doc), table);
System::String outputPath = outputDataDir + u"CloneTable.CloneCompleteTable.doc";
// Save the document to disk.
doc->Save(outputPath);

Below example shows how to make a clone of the last row of a table and append it to the table. You can download the template file of this example from here.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>(inputDataDir + u"Table.SimpleTable.doc");
// Retrieve the first table in the document.
System::SharedPtr<Table> table = System::DynamicCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// Clone the last row in the table.
System::SharedPtr<Row> clonedRow = System::DynamicCast<Row>((System::StaticCast<Node>(table->get_LastRow()))->Clone(true));
// Remove all content from the cloned row's cells. This makes the row ready for
// New content to be inserted into.
for (System::SharedPtr<Cell> cell : System::IterateOver<System::SharedPtr<Cell>>(clonedRow->get_Cells()))
{
cell->RemoveAllChildren();
}
// Add the row to the end of the table.
table->AppendChild(clonedRow);
System::String outputPath = outputDataDir + u"CloneTable.CloneLastRow.doc";
// Save the document to disk.
doc->Save(outputPath);

If you are looking at creating tables in the document which dynamically grow with each record from your data source, then the above method is not advised. Instead, the desired output is achieved more easily by using Mail Merge with Regions. You can learn more about this technique under Mail Merge with Regions Explained.

Inserting a Table from HTML

Aspose.Words supports inserting content into a document from an HTML source by using the DocumentBuilder.InsertHtml method. The input can be a full HTML page or just a partial snippet. Using this method we can insert tables into our document by using table elements e.g <table>, <tr>, <td>. Below example shows how to insert a table in a document from a string containing HTML tags.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
// The path to the documents directory.
System::String outputDataDir = GetOutputDataDir_WorkingWithTables();
System::SharedPtr<Document> doc = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(doc);
// Insert the table from HTML. Note that AutoFitSettings does not apply to tables
// Inserted from HTML.
builder->InsertHtml(u"<table><tr><td>Row 1, Cell 1</td><td>Row 1, Cell 2</td></tr><tr><td>Row 2, Cell 2</td><td>Row 2, Cell 2</td></tr></table>");
System::String outputPath = outputDataDir + u"InsertTableFromHtml.doc";
// Save the document to disk.
doc->Save(outputPath);

Comparison of Insertion Techniques

As described in previous articles, Aspose.Words provides several methods for inserting new tables into a document. Each have their advantages and disadvantages, so often the choice of which to use depends on your situation. The table below can give you an idea of each technique.

Method Advantages Disadvantages
DocumentBuilder (DocumentBuilder.StartTable) The standard method of inserting tables and other document content. Sometimes hard to create many varieties of tables at the same time with the same instance of the builder.
Table(Table) Fits in better with surrounding code that creates and inserts nodes directly into the DOM without the use of DocumentBuilder. The table is created “blank”. Before most operations are performed Table.EnsureMinimum must be called to create any missing child nodes.
Cloning (Table.Clone) Can create a copy of an existing table while retaining all formatting on rows and cells. The appropriate child nodes must be removed before the table is ready for use.

Extracting Plain Text from a Table

A Table like any other node in Aspose.Words has access to a Range object. Using this object, you can call methods over the entire table range to extract the table as plain text. The Range.Text property is used for this purpose. Below example shows how to print the text range of a table.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>(documentPath);
// Get the first table in the document.
System::SharedPtr<Table> table = System::DynamicCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// The range text will include control characters such as "\a" for a cell.
// You can call ToString and pass SaveFormat.Text on the desired node to find the plain text content.
// Print the plain text range of the table to the screen.
std::cout << "Contents of the table: " << std::endl << table->get_Range()->get_Text().ToUtf8String() << std::endl;

Below example shows how to print the text range of row and table elements.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
// Print the contents of the second row to the screen.
std::cout << "Contents of the row: " << std::endl << table->get_Rows()->idx_get(1)->get_Range()->get_Text().ToUtf8String() << std::endl;
// Print the contents of the last cell in the table to the screen.
std::cout << "Contents of the cell: " << std::endl << table->get_LastRow()->get_LastCell()->get_Range()->get_Text().ToUtf8String() << std::endl;

Replacing Text in a Table

Using a table’s range object you can replace text within the table. However, there are currently restrictions which prevent any replacement with special characters being made so care must be taken to ensure that the replacement string does not carry over more than one paragraph or cell. If such a replacement is made which spans across multiple nodes, such as paragraphs or cells, then an exception is thrown.

Normally the replacement of text should be done at the cell level (per cell) or at the paragraph level.

Below example shows how to replace all instances of a string of text in a table and cell.

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
System::SharedPtr<Document> doc = System::MakeObject<Document>(documentPath);
// Get the first table in the document.
System::SharedPtr<Table> table = System::DynamicCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// Replace any instances of our string in the entire table.
table->get_Range()->Replace(u"Carrots", u"Eggs", System::MakeObject<FindReplaceOptions>(FindReplaceDirection::Forward));
// Replace any instances of our string in the last cell of the table only.
table->get_LastRow()->get_LastCell()->get_Range()->Replace(u"50", u"20", System::MakeObject<FindReplaceOptions>(FindReplaceDirection::Forward));
System::String outputPath = outputDataDir + u"ExtractOrReplaceText.ReplaceText.doc";
doc->Save(outputPath);

Tables in Microsoft Word

All versions of Microsoft Word provide special commands for inserting and working with tables. The exact location of these differs between older and newer versions of Microsoft Word but they are all present. These are some of the more common tasks required when working with tables in Microsoft Word.

Inserting a Table in Microsoft Word

To insert a table in Microsoft Word 2003 and earlier:

  1. Click the Table menu from the top toolbar.
  2. Click Insert and then Table.
  3. Fill in the appropriate values and press Ok to insert the table.

To insert a table in Microsoft Word 2007 and later:

  1. Click the Insert tab.
  2. Choose the Tables drop-down menu.
  3. Select Insert Table.
  4. Fill in the appropriate values and press Ok to insert the table.

Removing a Table or Table Elements in Microsoft Word

To remove a table or individual table elements in Microsoft Word 2003 and earlier:

  1. Click inside the table in the position that you want.
  2. Click the Table menu from the top toolbar.
  3. Click Delete.
  4. Choose the menu item of the element you want to delete. For instance, choosing Table will remove the entire table from the document.

To remove a table or individual table elements in Microsoft Word 2007 and later:

  1. Click inside the table at the desired position.
  2. The Layout tab should appear. Click this tab.
  3. Click the Delete drop-down menu.
  4. Choose the menu item of the element you want to delete. For instance, choosing Delete Table will remove the entire table from the document.

Merging Cells in a Table in Microsoft Word

  1. Select the cells to be merged by dragging the cursor over the cells.
  2. Right click on the selection.
  3. Select Merge Cells from the popup menu.

Using the AutoFit feature in Microsoft Word

To use the AutoFit feature to automatically size a table in Microsoft Word:

  1. Right-click anywhere inside the desired table.
  2. Select AutoFit from the popup menu.
  3. Select the desired autofit option
    1. AutoFit to Contents fits the table around content.
    2. AutoFit to Window resizes the table so it fills the available page width between the left and right margins.
    3. Fixed Column Width sets each column width to an absolute value. This means even if the content within the cells were to change the width of each column in the table will stay the same.