Get the list numbers from Word document? - c#

I'm using Microsoft.Office.Interop.Word to parse a Word 2010 document. I'm grabbing all the text from every cell in the first column of every table on every page. The problem I'm having, though, is that when I get the text, it's not including the list numbers. For example, the text in my table looks like this:
My program loops through the document and grabs the text from every cell in the first column. Instead of getting "1. Introduction", though, I'm getting "Introduction". Here's what the data looks like that I'm getting:
As you can see, I'm not getting the list numbers, just the text (i.e. "Introduction" instead of "1. Introduction").
Here's the loop I'm using to get the data:
// Loop through each table in the document,
// grab only text from cells in the first column
// in each table.
foreach (Table tb in docs.Tables)
{
for (int row = 1; row <= tb.Rows.Count; row++)
{
var cell = tb.Cell(row, 1);
var text = cell.Range.Text;
dt.Rows.Add(text);
}
}
Can someone offer any pointers on how to grab the list numbers from each cell, as well as the text? I imagine it will be something like this:
var text = cell.Range.ListNumber + " " + cell.Range.Text;
...but I can't figure it out, exactly.

Found the answer. I had to get the ListString value:
// Loop through each table in the document,
// grab only text from cells in the first column
// in each table.
foreach (Table tb in docs.Tables)
{
for (int row = 1; row <= tb.Rows.Count; row++)
{
var cell = tb.Cell(row, 1);
var listNumber = cell.Range.ListFormat.ListString;
var text = listNumber + " " + cell.Range.Text;
dt.Rows.Add(text);
}
}

Related

C#, ClosedXML. Taking cell addresses from an Excel sheet, and taking data from a data table, and use this addresses and datas to fill a template file

Addresses Excel
I have an issue with my c# code with ClosedXML, which takes cell addresses from another excel file, takes data from another excel table, and writes data to an excel file which is a template but while taking the addresses, it's sorting them, if the data table has a certain value, it's should write the value to a certain address. For example, if the C5 cell in the data table has "SPHERE", it's gonna write to value to K1 cell, if the C5 cell in the data table has "BODY", it's gonna write to value to K5 cell, if the C5 cell in the data table is empty, it's not gonna use that parameter and directly write the value to G3, this example can be multiplied by different parameters.
But the problem is when it takes data from a cell first, it fills the defined cell in the if and saves the file, when it comes to a second file, it fills the first cell with the value before, then fills the second cell. It iterates like this until the parameter has different value.
public void Read(string path, string directory, bool savewithdatetime)
{
// Open workbook and get worksheet at index 1
XLWorkbook excelBook = new XLWorkbook(path);
IXLWorksheet excelWorkSheet = excelBook.Worksheet(1);
excelWorkSheet.Row(1).Delete();
// Get number of rows with data
int excelRowCount = excelWorkSheet.RowsUsed().Count();
// Open data source and get the worksheet at index 1
XLWorkbook dataSource = new XLWorkbook(Application.StartupPath + "/dataSource.xlsx");
IXLWorksheet dataSourceWS = dataSource.Worksheet(1);
List<string> ifList = new List<string>();
List<string> parameterList = new List<string>();
List<string> fromList = new List<string>();
List<string> toList = new List<string>();
for (int i = 1; i <= dataSourceWS.RowsUsed().Count(); i++)
{
ifList.Add(dataSourceWS.Cell("A" + i).Value.ToString());
parameterList.Add(dataSourceWS.Cell("D" + i).Value.ToString());
fromList.Add(dataSourceWS.Cell("B" + i).Value.ToString());
toList.Add(dataSourceWS.Cell("C" + i).Value.ToString());
}
string time = TimeStamp(savewithdatetime);
// Iterate over each row in the excelWorkSheet
for (int row = 1; row <= excelRowCount; row++)
{
// Reset templateWS to the original template
templateWS = template.Worksheet(1);
// Iterate through the data source rows
for (int i = 0; i < fromList.Count; i++)
{
// Check if the cell at the given address in excelWorkSheet is empty
if (string.IsNullOrEmpty(excelWorkSheet.Cell(ifList[i]).Value.ToString()))
{
// If empty, skip to the next iteration
continue;
}
// Check if the value of the cell at the given address in excelWorkSheet matches the value of the cell at the corresponding address in parameterList
else if (parameterList[i] == excelWorkSheet.Cell(ifList[i]).Value.ToString())
{
// If the values match, set the value of the cell at the corresponding address in toList to the value of the cell at the corresponding address in fromList
templateWS.Cell(toList[i]).Value = excelWorkSheet.Cell(fromList[i]).Value;
}
}
// Save template workbook as new file with incremented index in the specified directory
template.SaveAs(directory + "/Test results" + time + "/Test result-[" + (row) + "].xlsx");
if (row == excelRowCount)
{
break;
}
// Delete the first row of the excelWorkSheet so that the next iteration will use the next row of data
excelWorkSheet.Row(1).Delete();
}
// Clear the lists and collect garbage to free up memory
ifList.Clear();
fromList.Clear();
parameterList.Clear();
toList.Clear();
GC.Collect();
}

Get a cell location from a given value and find the value on the right from cell location from Excel using EPPlus and Linq

This is what I want to have
Find the location of the value "arriere" in an Excel sheet and get the value next to it.
column I row 35 = "arriere"
column J row 35 = 1456.00
Right now I'm using the following code :
using (var package = new ExcelPackage(f.FullName))
{
var worksheet = package.Workbook.Worksheets[0];
var montantArriere = from cell in worksheet.Cells["G:L"]
where cell.Value?.ToString() == "Total Arriéré"
select worksheet.Cells[cell.Start.Row, 10].Value;
}
The code works but if the value "arriere" change of column I won't be able to find the value next to it since the cell.Start.Row is set by 10 from the start.
Is there any way to have the value next to "arriere" more dynamically?
You can use Offset on cell to get a cell based on the offset you choose. (row, column)
using (var package = new ExcelPackage(f.FullName))
{
var worksheet = package.Workbook.Worksheets[0];
var montantArriere = from cell in worksheet.Cells["G:L"]
where cell.Value?.ToString() == "Total Arriéré"
select cell.Offset(0,1).Value;
}

Adding Array to Existing DataTable

I have a DataTable, dtHOURS, that consists of two columns of data passed from an SQL database and I am trying to include a third column that consists of calculated values within the array, hours. I've looked at many similar asked questions, but none of the solutions seem to work in my case. I've confirmed that the correct values are being stored in the array, but I can't seem to populate those values within column "Total Hours". All the row data comes out blank for this column.
Any help would be appreciated.
Thank you in advance.
//Create new column and row for the "Total Hours" in data table
DataColumn TotalHoursCol;
DataRow TotalHoursRow;
// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
TotalHoursCol = new DataColumn();
TotalHoursCol.DataType = System.Type.GetType("System.Double");
TotalHoursCol.ColumnName = "Total Hours";
// Add the Column to the Table.
dtHOURS.Columns.Add(TotalHoursCol);
//This loop calculates the total hours for all jobs and adds them to the data table
for (int i = 1; i < numberOfRecordsHours; i++)
{
//Console.WriteLine(dtHOURS.Rows[i]["ID"]);
//Console.WriteLine(dtHOURS.Rows[i]["ACT_RUN_HRS"]);
if ((Convert.ToString(dtHOURS.Rows[i]["ID"])) == (Convert.ToString(dtHOURS.Rows[i-1]["ID"])))
{
hours[i] = (Convert.ToDouble(dtHOURS.Rows[i]["ACT_RUN_HRS"])) + (hours[i-1]);
//Console.WriteLine(hours[i]);
}
else
{
hours[i] = 0;
//Console.WriteLine("NEW JOB");
}
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
//Console.WriteLine(dtHOURS.Rows[i]["Total Hours"]);
}
If I am understanding the problem correctly, it looks like you are adding a new row instead of assigning to your new column.
Instead of
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
Just put
dtHOURS.Rows[i]["Total Hours"] = hours[i];

Select range in aspose

Do you know an equivalent to VBA code:
Range(Selection, Selection.End(xlToRight)).Select
In Aspose.Cells. It seems that its only possible to select the last cell in the entire row:
public Aspose.Cells.Cell EndCellInRow ( Int32 rowIndex )
Or the last cell on the right within a range:
public Aspose.Cells.Cell EndCellInRow ( Int32 startRow, Int32 endRow, Int32 startColumn, Int32 endColumn )
but then you must know more or less how big your table is going to be.
I found this from 2009: http://www.aspose.com/community/forums/permalink/196519/196405/showthread.aspx but that will not resolve my problem as I may have many tables in a sheet both horizontally and vertiacally. And I can't predict where they are going to be.
Edit1:
Sorry if this is dumb question, but ctrl+shift+arrow is such a common operation that I can't believe it would be not implemented so I'm making sure I really have to re-invent the wheel.
Aspose.Cells provides the list of tables in a worksheet using property named 'Worksheet.ListObjects'. 'ListObjects' is a colloection of 'ListObject' type which represents a Table in an excel sheet. That means if one has more than one Tables in a worksheet, the ListObjects collection will give access to every table in the worksheet very conveniently. Each 'ListObject' in turn contains a property named 'DataRange' which specifies all the cells inside a Table. For the sake of convenience DataRange can be used for following operations on a Table:
To apply styles/formatting on the cells in Table
To get the data values
Merge or move the cells in Range
Export contents
To get enumerator to traverse through Table cells
To make selection of cells from DataRange, you can traverse using DataRange to get all the cells in a Row (This could also be done for a column)
Applying any operation on Table cells like after selecting cells using Ctrl+Shift+Arrow, could be performed using a workbook object as follows:
Workbook workbook = new Workbook(new FileStream("book1.xls", FileMode.Open));
if (workbook.Worksheets[0].ListObjects.Count > 0)
{
foreach (ListObject table in workbook.Worksheets[0].ListObjects)
{
Style st = new Style();
st.BackgroundColor = System.Drawing.Color.Aqua;
st.ForegroundColor = System.Drawing.Color.Black;
st.Font.Name = "Agency FB";
st.Font.Size = 16;
st.Font.Color = System.Drawing.Color.DarkRed;
StyleFlag stFlag = new StyleFlag();
stFlag.All = true;
table.DataRange.ApplyStyle(st, stFlag);
}
}
workbook.Save("output.xls");
There is also some worthy information available in Aspose docs about Table styles and applying formatting on a ListObject. For getting last Table cell in a certain row or column, I am sure this will help:
int iFirstRowIndex = table.DataRange.FirstRow;
int iFirstColumnIndex = table.DataRange.FirstColumn;
int iLastRowIndex = table.DataRange.RowCount + iFirstRowIndex;
int iLastColumnIndex = table.DataRange.ColumnCount + iFirstColumnIndex;
for (int rowIndex = 0; rowIndex < table.DataRange.RowCount; rowIndex++)
{
//Get last cell in every row of table
Cell cell = worksheet.Cells.EndCellInColumn(rowIndex + iFirstRowIndex, rowIndex + iFirstRowIndex, (short)iFirstColumnIndex, (short)(iLastColumnIndex - 1));
//display cell value
System.Console.WriteLine(cell.Value);
}

Adding rows to datagridview with combox

I have a DataGridView that I am programmatically adding rows to.
There are three columns: a TextBox column and two ComboBox columns. I've got the 1st and 3rd columns down pat because I know the text I am going to add. For the 3rd column (ComboBox) every row has the same 3 ComboBox item options.
It's the second column I'm having trouble with, where I need to have a different set of ComboBox items for each row. Is this possible?
I'll add my code below, let me know if anything's unclear. I'm looping through a list of folders, comparing the current name with a dataset value and needing to add the dataset name to the combobox items for the row if they "match".
//Loop through each local folder
string thisLocalFolder = Path.GetFileName(localFoldersArray[j].ToString());
//helpdeskCompanyNameMatchColumn.Items.Clear();
for (int i = 0; i < companyDataSet.Tables[0].Rows.Count; i++)
{
//Loop through each downloaded company name to compare
string dataComapanyToCompany = companyDataSet.Tables[0].Rows[i]["Company"].ToString();
if (dataComapanyToCompany.Contains(thisLocalFolder))
{
Console.WriteLine("Match: " + thisLocalFolder + " is close enough to " + dataComapanyToCompany);
//Add the possible match to the combobox item options, for this row
helpdeskCompanyNameMatchColumn.Items.Add(dataComapanyToCompany);
}
}

Categories

Resources