简体   繁体   中英

SpreadsheetLight C# - Load Excel Table by Name into DataTable

I am quite pleased with SpreadsheetLight. However I cannot help but think I've overlooked something. In Excel, you can "Format As Table" and then when the table is selected the "Table Tools - Design" tab appears. You can change Table Name which is great.

However I have struggled to find a straight forward way of using SpreadsheetLight to load an excel file and then get tables on a worksheet.

Is there no other way besides resorting to reflection?

using SpreadsheetLight;

~~~~~~~
~~~~~~~
~~~~~~~

public DataTable LoadExcelFileTable(string FullFileName)
{
    //Load Excel File, get Table Names, compare, Load matching table name into DataTable and return.
    string tableName = "Table1";

    SLDocument sl = new SLDocument(FullFileName);
    sl.SelectWorksheet(SLDocument.DefaultFirstSheetName);


    DataTable excelTableDT = GetExcelTablesOfSelectedWorksheet(sl);

    //Using table dt can extract data....


    return null;  //Placeholder for now
}

private DataTable GetExcelTablesOfSelectedWorksheet(SLDocument sl)
{
    string sci = "StartColumnIndex";
    string sri = "StartRowIndex";
    string eci = "EndColumnIndex";
    string eri = "EndRowIndex";

    DataTable excelTableDT = new DataTable();
    excelTableDT.Columns.Add("DisplayName");
    excelTableDT.Columns.Add(sci, typeof(int)); // 1 == A, 2 == B
    excelTableDT.Columns.Add(sri, typeof(int));    // 1 == 1, 2 == 2
    excelTableDT.Columns.Add(eci, typeof(int));   // 1 == A, 2 == B
    excelTableDT.Columns.Add(eri, typeof(int));      // 1 == 1, 2 == 2

    //Appears it's not made public, we cannot normally access tables and then by name determine start and end cells.
    //Reflection to the rescue
    FieldInfo slwsFieldInfo = typeof(SLDocument).GetField("slws", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    if (slwsFieldInfo != null)
    {
        var b = slwsFieldInfo.GetValue(sl);
        if (b != null)
        {
            var TablesPropInfo = b.GetType().GetProperty("Tables", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            if (TablesPropInfo != null)
            {
                var oTables = TablesPropInfo.GetValue(b);
                if (oTables != null && oTables is List<SLTable> Tables)
                {
                    if (Tables != null)
                    {
                        foreach (SLTable slTable in Tables)
                        {
                            //Get the info we need
                            string DisplayName = slTable.DisplayName;
                            int StartColumnIndex = Reflection_TryGetIntPropertyValue(slTable, sci);
                            int StartRowIndex = Reflection_TryGetIntPropertyValue(slTable, sri);
                            int EndColumnIndex = Reflection_TryGetIntPropertyValue(slTable, eci);
                            int EndRowIndex = Reflection_TryGetIntPropertyValue(slTable, eri);
                            //Add to DataTable
                            excelTableDT.Rows.Add(new object[] { DisplayName, StartColumnIndex, StartRowIndex, EndColumnIndex, EndRowIndex });
                        }
                    }
                }
            }
        }
    }
    return excelTableDT;
}

private int Reflection_TryGetIntPropertyValue(object o, string propertyName)
{
    int x = -1;

    try
    {
        var propInfo = o.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (propInfo != null)
        {
            object val = propInfo.GetValue(o);
            if (val != null && val is int yay)
            {
                x = yay;
            }
        }
    }
    catch { }

    return x;
}

After some in-depth research, I learned how to get tables on all spreadsheets using the Microsoft "DocumentFormat.OpenXml" which is what SpreadsheetLight uses behind the scenes. At this point I'm comfortable using this method over reflection.

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

~~~~~~
~~~~~~
~~~~~~

private DataTable GetExcelTablesFromWorksheets(string FullFileName)
{
    DataTable excelTablesDT = new DataTable();
    excelTablesDT.Columns.Add("Spreadsheet");
    excelTablesDT.Columns.Add("TableName");
    excelTablesDT.Columns.Add("CellRange");
    excelTablesDT.Columns.Add("HasHeader", typeof(bool));

    using (SpreadsheetDocument sd = SpreadsheetDocument.Open(FullFileName, false))
    {
        if(sd != null && sd.WorkbookPart != null)
        {
            IEnumerable<Sheet> sheets = sd.WorkbookPart.Workbook.Sheets.Elements<Sheet>();
            IEnumerable<WorksheetPart> wsps = sd.WorkbookPart.WorksheetParts;
            if (wsps != null)
            {
                foreach (WorksheetPart wsp in wsps)
                {
                    if (wsp != null)
                    {
                        IEnumerable<TableDefinitionPart> tdps = wsp.TableDefinitionParts;
                        if (tdps != null)
                        {
                            foreach (TableDefinitionPart tdp in tdps)
                            {
                                if (tdp != null)
                                {
                                    Table t = tdp.Table;
                                    if (t != null)
                                    {
                                        string Spreadsheet = "";
                                        string SpreadsheetId = sd.WorkbookPart.GetIdOfPart(wsp);
                                        Sheet currentSheet = sheets.FirstOrDefault(s => s.Id.HasValue && s.Id.Value.Equals(SpreadsheetId, StringComparison.OrdinalIgnoreCase));
                                        if(currentSheet != null)
                                        {
                                            Spreadsheet = currentSheet.Name;
                                        }
                                        string TableName = t.DisplayName;
                                        string CellRange = t.Reference.HasValue ? t.Reference.Value : "";
                                        bool hasHeader = !(t.HeaderRowCount != null && t.HeaderRowCount.HasValue && t.HeaderRowCount.Value == 0);
                                        //Add to DataTable
                                        excelTablesDT.Rows.Add(new object[] { Spreadsheet, TableName, CellRange, hasHeader });
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return excelTablesDT;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM