首页 文章

使用Open XML从C#中的Excel到DataTable

提问于
浏览
37

我正在使用Visual Studio 2008,我需要使用Open XML SDK 2.0从Excel工作表创建 DataTable . 我需要使用带有工作表第一行的DataTable列创建它,并使用其余值完成它 .

有没有人有一个示例代码或链接可以帮助我这样做?

6 回答

  • 2

    我认为这应该做你所要求的 . 如果您有共享字符串,那么另一个函数就是处理,我假设您在列 Headers 中执行此操作 . 不确定这是完美的,但我希望它有所帮助 .

    static void Main(string[] args)
    {
        DataTable dt = new DataTable();
    
        using (SpreadsheetDocument spreadSheetDocument = SpreadsheetDocument.Open(@"..\..\example.xlsx", false))
        {
    
            WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart;
            IEnumerable<Sheet> sheets = spreadSheetDocument.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
            string relationshipId = sheets.First().Id.Value;
            WorksheetPart worksheetPart = (WorksheetPart)spreadSheetDocument.WorkbookPart.GetPartById(relationshipId);
            Worksheet workSheet = worksheetPart.Worksheet;
            SheetData sheetData = workSheet.GetFirstChild<SheetData>();
            IEnumerable<Row> rows = sheetData.Descendants<Row>();
    
            foreach (Cell cell in rows.ElementAt(0))
            {
                dt.Columns.Add(GetCellValue(spreadSheetDocument, cell));
            }
    
            foreach (Row row in rows) //this will also include your header row...
            {
                DataRow tempRow = dt.NewRow();
    
                for (int i = 0; i < row.Descendants<Cell>().Count(); i++)
                {
                    tempRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i-1));
                }
    
                dt.Rows.Add(tempRow);
            }
    
        }
        dt.Rows.RemoveAt(0); //...so i'm taking it out here.
    
    }
    
    
    public static string GetCellValue(SpreadsheetDocument document, Cell cell)
    {
        SharedStringTablePart stringTablePart = document.WorkbookPart.SharedStringTablePart;
        string value = cell.CellValue.InnerXml;
    
        if (cell.DataType != null && cell.DataType.Value == CellValues.SharedString)
        {
            return stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
        }
        else
        {
            return value;
        }
    }
    
  • 0

    嗨以上代码工作正常,除了一个更改

    替换下面的代码行

    tempRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i-1));
    

    tempRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i));
    

    如果使用(i-1),它将抛出异常:

    specified argument was out of the range of valid values. parameter name index.
    
  • 61
    Public Shared Function ExcelToDataTable(filename As String) As DataTable
            Try
    
                Dim dt As New DataTable()
    
                Using doc As SpreadsheetDocument = SpreadsheetDocument.Open(filename, False)
    
                    Dim workbookPart As WorkbookPart = doc.WorkbookPart
                    Dim sheets As IEnumerable(Of Sheet) = doc.WorkbookPart.Workbook.GetFirstChild(Of Sheets)().Elements(Of Sheet)()
                    Dim relationshipId As String = sheets.First().Id.Value
                    Dim worksheetPart As WorksheetPart = DirectCast(doc.WorkbookPart.GetPartById(relationshipId), WorksheetPart)
                    Dim workSheet As Worksheet = worksheetPart.Worksheet
                    Dim sheetData As SheetData = workSheet.GetFirstChild(Of SheetData)()
                    Dim rows As IEnumerable(Of Row) = sheetData.Descendants(Of Row)()
    
                    For Each cell As Cell In rows.ElementAt(0)
                        dt.Columns.Add(GetCellValue(doc, cell))
                    Next
    
                    For Each row As Row In rows
                        'this will also include your header row...
                        Dim tempRow As DataRow = dt.NewRow()
    
                        For i As Integer = 0 To row.Descendants(Of Cell)().Count() - 1
                            tempRow(i) = GetCellValue(doc, row.Descendants(Of Cell)().ElementAt(i))
                        Next
    
                        dt.Rows.Add(tempRow)
                    Next
                End Using
    
                dt.Rows.RemoveAt(0)
    
                Return dt
    
            Catch ex As Exception
                Throw ex
            End Try
        End Function
    
    
        Public Shared Function GetCellValue(document As SpreadsheetDocument, cell As Cell) As String
            Try
    
                If IsNothing(cell.CellValue) Then
                    Return ""
                End If
    
                Dim value As String = cell.CellValue.InnerXml
    
                If cell.DataType IsNot Nothing AndAlso cell.DataType.Value = CellValues.SharedString Then
                    Dim stringTablePart As SharedStringTablePart = document.WorkbookPart.SharedStringTablePart
                    Return stringTablePart.SharedStringTable.ChildElements(Int32.Parse(value)).InnerText
                Else
                    Return value
                End If
    
            Catch ex As Exception
                Return ""
            End Try
        End Function
    
  • 14

    此解决方案适用于没有空单元格的电子表格 .

    要处理空单元格,您需要替换此行:

    tempRow[i] = GetCellValue(spreadSheetDocument, row.Descendants<Cell>().ElementAt(i-1));
    

    用这样的东西:

    Cell cell = row.Descendants<Cell>().ElementAt(i);
    int index = CellReferenceToIndex(cell);
    tempRow[index] = GetCellValue(spreadSheetDocument, cell);
    

    并添加此方法:

    private static int CellReferenceToIndex(Cell cell)
    {
        int index = 0;
        string reference = cell.CellReference.ToString().ToUpper();
        foreach (char ch in reference)
        {
            if (Char.IsLetter(ch))
            {
                int value = (int)ch - (int)'A';
                index = (index == 0) ? value : ((index + 1) * 26) + value;
            }
            else
                return index;
        }
        return index;
    }
    
  • -1

    这是我的完整解决方案,其中也考虑了空单元 .

    public static class ExcelHelper
            {
                //To get the value of the cell, even it's empty. Unable to use loop by index
                private static string GetCellValue(WorkbookPart wbPart, List<Cell> theCells, string cellColumnReference)
                {
                    Cell theCell = null;
                    string value = "";
                    foreach (Cell cell in theCells)
                    {
                        if (cell.CellReference.Value.StartsWith(cellColumnReference))
                        {
                            theCell = cell;
                            break;
                        }
                    }
                    if (theCell != null)
                    {
                        value = theCell.InnerText;
                        // If the cell represents an integer number, you are done. 
                        // For dates, this code returns the serialized value that represents the date. The code handles strings and 
                        // Booleans individually. For shared strings, the code looks up the corresponding value in the shared string table. For Booleans, the code converts the value into the words TRUE or FALSE.
                        if (theCell.DataType != null)
                        {
                            switch (theCell.DataType.Value)
                            {
                                case CellValues.SharedString:
                                    // For shared strings, look up the value in the shared strings table.
                                    var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
                                    // If the shared string table is missing, something is wrong. Return the index that is in the cell. Otherwise, look up the correct text in the table.
                                    if (stringTable != null)
                                    {
                                        value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
                                    }
                                    break;
                                case CellValues.Boolean:
                                    switch (value)
                                    {
                                        case "0":
                                            value = "FALSE";
                                            break;
                                        default:
                                            value = "TRUE";
                                            break;
                                    }
                                    break;
                            }
                        }
                    }
                    return value;
                }
    
                private static string GetCellValue(WorkbookPart wbPart, List<Cell> theCells, int index)
                {
                    return GetCellValue(wbPart, theCells, GetExcelColumnName(index));
                }
    
                private static string GetExcelColumnName(int columnNumber)
                {
                    int dividend = columnNumber;
                    string columnName = String.Empty;
                    int modulo;
                    while (dividend > 0)
                    {
                        modulo = (dividend - 1) % 26;
                        columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
                        dividend = (int)((dividend - modulo) / 26);
                    }
                    return columnName;
                }
    
                //Only xlsx files
                public static DataTable GetDataTableFromExcelFile(string filePath, string sheetName = "")
                {
                    DataTable dt = new DataTable();
                    try
                    {
                        using (SpreadsheetDocument document = SpreadsheetDocument.Open(filePath, false))
                        {
                            WorkbookPart wbPart = document.WorkbookPart;
                            IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
                            string sheetId = sheetName != "" ? sheets.Where(q => q.Name == sheetName).First().Id.Value : sheets.First().Id.Value;
                            WorksheetPart wsPart = (WorksheetPart)wbPart.GetPartById(sheetId);
                            SheetData sheetdata = wsPart.Worksheet.Elements<SheetData>().FirstOrDefault();
                            int totalHeaderCount = sheetdata.Descendants<Row>().ElementAt(0).Descendants<Cell>().Count();
                            //Get the header                    
                            for (int i = 1; i <= totalHeaderCount; i++)
                            {
                                dt.Columns.Add(GetCellValue(wbPart, sheetdata.Descendants<Row>().ElementAt(0).Elements<Cell>().ToList(), i));
                            }
                            foreach (Row r in sheetdata.Descendants<Row>())
                            {
                                if (r.RowIndex > 1)
                                {
                                    DataRow tempRow = dt.NewRow();
    
                                    //Always get from the header count, because the index of the row changes where empty cell is not counted
                                    for (int i = 1; i <= totalHeaderCount; i++)
                                    {
                                        tempRow[i - 1] = GetCellValue(wbPart, r.Elements<Cell>().ToList(), i);
                                    }
                                    dt.Rows.Add(tempRow);
                                }
                            }                    
                        }
                    }
                    catch (Exception ex)
                    {
    
                    }
                    return dt;
                }
            }
    
  • 2

    如果rows值为null或为空,则获取值错误的工作 .

    所有列都填充了数据,如果它正常工作 . 但也许所有行都没有

相关问题