Saltar al contenido

C # OPEN XML: las celdas vacías se omiten mientras se obtienen datos de EXCEL a DATATABLE

Intenta interpretar el código bien previamente a usarlo a tu trabajo y si tdeseas aportar algo puedes dejarlo en la sección de comentarios.

Solución:

Si hubiera datos en todas las celdas de una fila, entonces todo funciona bien. En el momento en que tienes una sola celda vacía en una fila, las cosas se vuelven locas.

Por qué está sucediendo en primer lugar?

Esto se debe a que en el siguiente código:

row.Descendants().Count()

El Count() es el numero de no vacio celdas pobladas (no todas las columnas). Entonces, cuando pases row.Descendants().ElementAt(i) como argumento para GetCellValue método:

GetCellValue(spreadSheetDocument, row.Descendants().ElementAt(i));

Entonces encontrará el contenido de la siguiente no vacio celda poblada (no necesariamente lo que hay en ese índice de columna, i) por ejemplo, si la primera columna está vacía y llamamos ElementAt(1), devuelve el valor en la segunda columna y toda la lógica se estropea.

Solución: tenemos que lidiar con la aparición de celdas vacías: Esencialmente, necesitamos averiguar el índice de columna original de la celda en caso de que hubiera celdas vacías antes. Por lo tanto, debe sustituir su código de bucle for como se muestra a continuación:

for (int i = 0; i < row.Descendants().Count(); i++)

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

con

for (int i = 0; i < row.Descendants().Count(); i++)

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

y agregue el siguiente método en su código que se usa en el fragmento de código modificado anterior para obtener el índice de columna original / correcto de cualquier celda:

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;

public void Read2007Xlsx()
        
            try
            
                DataTable dt = new DataTable();
                using (SpreadsheetDocument spreadSheetDocument = SpreadsheetDocument.Open(@"D:File.xlsx", false))
                
                    WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart;
                    IEnumerable sheets = spreadSheetDocument.WorkbookPart.Workbook.GetFirstChild().Elements();
                    string relationshipId = sheets.First().Id.Value;
                    WorksheetPart worksheetPart = (WorksheetPart)spreadSheetDocument.WorkbookPart.GetPartById(relationshipId);
                    Worksheet workSheet = worksheetPart.Worksheet;
                    SheetData sheetData = workSheet.GetFirstChild();
                    IEnumerable rows = sheetData.Descendants();
                    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();
                        int columnIndex = 0;
                        foreach (Cell cell in row.Descendants())
                        
                            // Gets the column index of the cell with data
                            int cellColumnIndex = (int)GetColumnIndexFromName(GetColumnName(cell.CellReference));
                            cellColumnIndex--; //zero based index
                            if (columnIndex < cellColumnIndex)
                            
                                do
                                
                                    tempRow[columnIndex] = ""; //Insert blank data here;
                                    columnIndex++;
                                
                                while (columnIndex < cellColumnIndex);
                            
                            tempRow[columnIndex] = GetCellValue(spreadSheetDocument, cell);

                            columnIndex++;
                        
                        dt.Rows.Add(tempRow);
                    
                
                dt.Rows.RemoveAt(0); //...so i'm taking it out here.
            
            catch (Exception ex)
            
            
        
        /// 
        /// Given a cell name, parses the specified cell to get the column name.
        /// 
        /// Address of the cell (ie. B2)
        /// Column Name (ie. B)
        public static string GetColumnName(string cellReference)
        
            // Create a regular expression to match the column name portion of the cell name.
            Regex regex = new Regex("[A-Za-z]+");
            Match match = regex.Match(cellReference);
            return match.Value;
        
        /// 
        /// Given just the column name (no row index), it will return the zero based column index.
        /// Note: This method will only handle columns with a length of up to two (ie. A to Z and AA to ZZ). 
        /// A length of three can be implemented when needed.
        /// 
        /// Column Name (ie. A or AB)
        /// Zero based index if the conversion was successful; otherwise null
        public static int? GetColumnIndexFromName(string columnName)
        

            //return columnIndex;
            string name = columnName;
            int number = 0;
            int pow = 1;
            for (int i = name.Length - 1; i >= 0; i--)
            
                number += (name[i] - 'A' + 1) * pow;
                pow *= 26;
            
            return number;
        
        public static string GetCellValue(SpreadsheetDocument document, Cell cell)
        
            SharedStringTablePart stringTablePart = document.WorkbookPart.SharedStringTablePart;
            if (cell.CellValue ==null)
            
            return "";
            
            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;
            
        

Acuérdate de que tienes la capacidad de glosar si te fue de ayuda.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *