Hello,I have a need to delete table columns from a table dynamically when creating my report.How can I basically do this and what do i need to know?
thank you
Andrew
There is no table column entity in MS Word binary file structure. One of your row can containg 3 cells and the next can containg 23 cells. There is no way you can tell that some cell belong to a particular column.
But if your table has rows with the same number of cells in each row then you can remove cells based on their index in the row. Just iterate over all rows of the table and remove the cell with the specified index from each row.
Hope this helps,
Hello,I found your advice very useful.I want to cut several columns off my table before I populate it, so how do I do this for no populated rows?
I need to just delete rows by using your method without adding any data and only delete what columns that are placed inside the template of my executewithRegions table setup that is markup of template table.
How is this done please?
Thank you Andrew
Hello,I tried this.
int reductionVar = -fieldsToReduceColumnsBy;
for (int i = 0; i < fieldsToReduceColumnsBy; i++)
{
table.Rows.RemoveAt(reductionVar); //error no rows defined
reductionVar--;
}
It appears I can’t reduce a table with rows associated of course. Is there a way to delete these from the template model before any data is added?
I don`t want to permanently alter my template from my full table display only save my generated table in a desired number of columns.
Thanks
Andrew
Sorry, I don’t understand what you are trying to do. Please explain your problem in a more detailed way. Also, please attach a sample of your template and some data in XML or any other form so that I could understand your task better.
Best regards,
Hello Vladimir, I am away from the office so I can`t upload my code at this time.
Although, all I am trying to do is delete the columns before I populate them.Like inspect the doc and set to only create a table that allows a row to have so many(reduced columns from template) columns on my determinations.
Like you have indicated to me in your explanation
“Just iterate over all rows of the table and remove the cell with the specified index from each row”
I wish to delete the columns before the I populate the rows not clean up after rows have been populated.
Thank you
Andrew
Do I get you right that you want to delete cells containing merge fields that are not present in your data source? Or, to put it even easier, to delete the cells in the particular table that contain merge fields with a particular name?
Anyway, as your request seems somewhat non-trivial, I would like to see an example of your template and data before creating any code snippet that fits your task.
Best regards,
Hello Vladimir,I have this table and wish to only generate rows instances for 4 columns not the last 2 of Product score and Combined score.
So I don’t wish to save my new document with these two columns of row data.
Columns:
| Supplier | Product | Covered Needs | Premium | Product Score | Combined Score|
Merge Fields:
«TableStart:SummaryTable»
«SupplierSummaryTable» | «ProductSummaryTable» | «CoveredNeedsSummaryTable» |
«PremiumSummaryTable» | «ProductScoreSummaryTable» | «CombinedScoreSummaryTable»
«TableEnd:SummaryTable»
Data is:
Suncorp | Yearly Renewable Term Life (Comprehensive Trauma) | 36 | $377.63 | 36 | 0
So I wish to keep my template but delete the columns from my ideal model of my table output to be saved.
Do I have to save my existing template as a new name then perform these duties or can I use my existing template in memory?
I am working in c#. I could send you a more graphically appealing version if you can’t understand i the diagram. The editor here doesn`t display tables and such well. I
Thank you
Andrew
Here, try the following method:
///
/// Deletes column with the specified number from the specidfied table.
/// The algorithm is based on the following assumptions:
/// - the table has two rows.
/// - first row contains column headers
/// - second row is marked up for merge with regions,
///
private void DeleteColumn(Table table, int colNumber)
{
// If removed column is the last in the row, then we need to move TableEnd field to the previous column.
if (colNumber == table.LastRow.Cells.Count - 1)
{
Cell cell = table.LastRow.Cells[colNumber];
Cell prevCell = table.LastRow.Cells[colNumber - 1];
foreach (FieldStart fieldStart in cell.GetChildNodes(NodeType.FieldStart, true, false))
{
if ((fieldStart.FieldType == FieldType.FieldMergeField) &&
(fieldStart.NextSibling.ToTxt().IndexOf("TableEnd") >= 0))
{
// Copy TableEnd field to the end of the previous cell.
for (Node node = fieldStart; node != null; node = node.NextSibling)
{
Node copiedNode = node.Clone(true);
prevCell.LastParagraph.AppendChild(copiedNode);
}
}
}
}
// Remove cell from the header row.
table.FirstRow.Cells[colNumber].Remove();
// Remove cell from the data row.
table.LastRow.Cells[colNumber].Remove();
}
To accomplish your task you need to call it in the following manner:
// Delete the 4th column (0-based).
DeleteColumn(doc.FirstSection.Body.Tables[0], 4);
// Delete the 5th, which became 4th after the previous call.
DeleteColumn(doc.FirstSection.Body.Tables[0], 4);
I have tested it and it works fine as far as I can see.
Hope this helps,
Hello Vladimir, I found your code snippet very useful. It really solves my problem
I am looking at the problem of finding the column Number from the merge fields in the template row.
That is finding the number of column when I have just the tableName and field name.
I wish to call a method to return this so a can call to Delete Column on the index returned by a finder method.
I think it might be something like this?*
for (i = 0; i < columnFieldMergeFieldNameList.Length; i++)
// find number of columns on name of merge field.
indxCol = doc.FirstSection.Body.Tables[0], columnFieldMergeFieldNameList;
DeleteColumn(doc.FirstSection.Body.Tables[0], indxCol);
How is this done?
Thank you
Andrew
Here it is:
///
/// Searches document for a cell containing merge field with the specified name.
/// Returns cell index in the row or -1, if the cell is not found.
///
private int GetColumnByMergFieldName(Document doc, string fieldName)
{
int colIndex = -1;
foreach (FieldStart fieldStart in doc.GetChildNodes(NodeType.FieldStart, true, false))
{
if ((fieldStart.FieldType == FieldType.FieldMergeField) &&
(fieldStart.NextSibling.ToTxt().IndexOf(fieldName) >= 0))
{
Cell cell = (Cell)fieldStart.GetAncestor(typeof(Aspose.Words.Cell));
if (cell != null)
{
colIndex = cell.ParentRow.IndexOf(cell);
break;
}
}
}
return colIndex;
}
The problem with fields is that they are not conventional document nodes but are made with a combination of several nodes. That is why it is somewhat untrivial task to work with them via the current model. We are going to improve this in the future versions however.
Best regards,
Hello Vladimir,thanks so much for your efforts so far I have used your snippets for successfull results.
I have a problem in calling the
DeleteColumn(Table table, int colNumber)
With a desired table. I need to know the index number of my table so I can call
DeleteColumn(doc.FirstSection.Body.Tables[0], indxCol);
with the correct table. i.e. I need to know the value to place in [0] instead of 0.
Therefore I need to find the table index containing my field. Then I can use the correct index number in doc.FirstSection.Body.Tables[0]
.
Thank you for help Vladimir
Andrew Beales
I see. Then maybe it is better to rewrite the last method as:
///
/// Searches document for a cell containing merge field with the specified name.
/// Returns cell or null, if the cell is not found.
///
private Cell GetCellByMergFieldName(Document doc, string fieldName)
{
Cell cell = null;
foreach (FieldStart fieldStart in doc.GetChildNodes(NodeType.FieldStart, true, false))
{
if ((fieldStart.FieldType == FieldType.FieldMergeField) &&
(fieldStart.NextSibling.ToTxt().IndexOf(fieldName) >= 0))
{
cell = (Cell)fieldStart.GetAncestor(typeof(Aspose.Words.Cell));
}
}
return cell;
}
and use it in the following way:
Cell cell = GetCellByMergFieldName(doc, "ProductScoreSummaryTable");
if (cell != null)
DeleteColumn(cell.ParentRow.ParentTable, cell.ParentRow.IndexOf(cell));
Hope this helps,
Hello **miklovan,**I have been working woth your DeleteColumn function quite extensively and pleased with it for most part up to now.I have found the need to have a table without some heading row, and only using a table with a single row and merge fields present.
Here when I have to delete a column on a table of just this case I get a null object reference when I attempt this last line of your DeleteColoumn function
// Remove cell from the data row.
table.LastRow.Cells[colNumber].Remove();
I there some special way to code this.
Hi
Try to use the following code to delete cell from table.
public void TestDeleteColumn()
{
Document doc = new Document(@"066_89116_andyalean1\NoTableHeadingRowProblem.doc");
DocumentBuilder builder = new DocumentBuilder(doc);
DeleteColumn("Merge2", builder);
doc.Save(@"066_89116_andyalean1\out.doc");
}
private void DeleteColumn(string FieldName, DocumentBuilder builder)
{
builder.MoveToMergeField(FieldName);
Cell cell = (Cell)builder.CurrentParagraph.ParentNode;
if (cell.IsLastCell)
{
int index = (cell.ParentNode as Row).IndexOf(cell);
Cell prevCell = (cell.ParentNode as Row).Cells[index - 1];
foreach (FieldStart fieldStart in cell.GetChildNodes(NodeType.FieldStart, true, false))
{
if ((fieldStart.FieldType == FieldType.FieldMergeField) &&
(fieldStart.NextSibling.ToTxt().IndexOf("TableEnd") >= 0))
{
// Copy TableEnd field to the end of the previous cell.
for (Node node = fieldStart; node != null; node = node.NextSibling)
{
Node copiedNode = node.Clone(true);
prevCell.LastParagraph.AppendChild(copiedNode);
}
}
}
}
// Remove cell from row.
cell.Remove();
}
I hope that it will help you.