Compartir a través de


Obtención de un encabezado de columna en un documento de hoja de cálculo

En este tema se muestra cómo usar las clases del SDK de Open XML para Office para recuperar un encabezado de columna en un documento de hoja de cálculo mediante programación.

Estructura básica de un documento spreadsheetML

La estructura básica de un SpreadsheetML documento consta de los Sheets elementos y Sheet , que hacen referencia a las hojas de cálculo del libro. Se crea un archivo XML independiente para cada hoja de cálculo. Por ejemplo, para SpreadsheetML un Workbook objeto que tiene dos hojas de cálculo denominados MySheet1 y MySheet2 se encuentra en el archivo Workbook.xml y se muestra en el ejemplo de código siguiente.

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
    <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
        <sheets>
            <sheet name="MySheet1" sheetId="1" r:id="rId1" /> 
            <sheet name="MySheet2" sheetId="2" r:id="rId2" /> 
        </sheets>
    </workbook>

Los archivos XML de hoja de cálculo contienen uno o varios elementos de nivel de bloque, como SheetData representa la tabla de celdas y contiene uno o varios Row elementos. contiene row uno o varios Cell elementos. Cada celda contiene un CellValue elemento que representa el valor de la celda. Por ejemplo, para SpreadsheetML la primera hoja de cálculo de un libro, que solo tiene el valor 100 en la celda A1, se encuentra en el archivo Sheet1.xml y se muestra en el ejemplo de código siguiente.

    <?xml version="1.0" encoding="UTF-8" ?> 
    <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <sheetData>
            <row r="1">
                <c r="A1">
                    <v>100</v> 
                </c>
            </row>
        </sheetData>
    </worksheet>

Con el SDK de Open XML, puede crear la estructura de documentos y el contenido que usa clases fuertemente tipadas que corresponden a SpreadsheetML elementos. Puede encontrar estas clases en el espacio de DocumentFormat.OpenXML.Spreadsheet nombres. En la tabla siguiente se enumeran los nombres de clase de las clases correspondientes a los workbookelementos , sheets, sheet, worksheety sheetData .

Elemento de SpreadsheetML Open XML SDK (clase) Descripción
<workbook/> DocumentFormat.OpenXML.Spreadsheet.Workbook El elemento raíz del elemento de documento principal.
<sheets/> DocumentFormat.OpenXML.Spreadsheet.Sheets El contenedor de las estructuras del nivel de bloque, como sheet, fileVersion y otras que se detallan en la especificación ISO/IEC 29500.
<sheet/> DocumentFormat.OpenXml.Spreadsheet.Sheet Una hoja que apunta a un archivo de definición de hoja.
<worksheet/> DocumentFormat.OpenXML.Spreadsheet. Worksheet Un archivo de definición de hoja que contiene los datos de la hoja.
<sheetData/> DocumentFormat.OpenXML.Spreadsheet.SheetData La tabla de celdas agrupadas por filas.
<row/> DocumentFormat.OpenXml.Spreadsheet.Row Una fila en una tabla de celdas.
<c/> DocumentFormat.OpenXml.Spreadsheet.Cell Una celda en una fila.
<v/> DocumentFormat.OpenXml.Spreadsheet.CellValue El valor de una celda.

Funcionamiento del código de ejemplo

El código de este procedimiento consta de tres métodos (funciones en Visual Basic): GetColumnHeading, GetColumnNamey GetRowIndex. Se llama a los dos últimos métodos desde dentro del GetColumnHeading método .

El GetColumnName método toma el nombre de celda como parámetro. Analiza el nombre de la celda para obtener el nombre de columna mediante la creación de una expresión regular para que coincida con la parte del nombre de columna del nombre de la celda. Para obtener más información sobre las expresiones regulares, vea Elementos de lenguaje de expresiones regulares.

// 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(cellName);

return match.Value;

El GetRowIndex método toma el nombre de celda como parámetro. Analiza el nombre de celda para obtener el índice de fila mediante la creación de una expresión regular para que coincida con la parte del nombre de celda que corresponde al índice de fila.

// Create a regular expression to match the row index portion the cell name.
Regex regex = new Regex(@"\d+");
Match match = regex.Match(cellName);

return uint.Parse(match.Value);

El GetColumnHeading método usa tres parámetros, la ruta de acceso completa al archivo de hoja de cálculo de origen, el nombre de la hoja de cálculo que contiene la columna especificada y el nombre de una celda de la columna para la que se va a obtener el encabezado.

El código obtiene el nombre de la columna de la celda especificada llamando al GetColumnName método . El código también obtiene las celdas de la columna y las ordena por fila mediante el GetRowIndex método .

// Get the column name for the specified cell.
string columnName = GetColumnName(cellName);

// Get the cells in the specified column and order them by row.
IEnumerable<Cell> cells = worksheetPart.Worksheet.Descendants<Cell>().Where(c => string.Compare(GetColumnName(c.CellReference?.Value), columnName, true) == 0)
    .OrderBy(r => GetRowIndex(r.CellReference) ?? 0);

Si existe la columna especificada, obtiene la primera celda de la columna mediante el First método . La primera celda contiene el encabezado. De lo contrario, la columna especificada no existe y el método devuelve null / Nothing

if (cells.Count() == 0)
{
    // The specified column does not exist.
    return null;
}

// Get the first cell in the column.
Cell headCell = cells.First();

Si el contenido de la celda se almacena en el SharedStringTablePart objeto , obtiene los elementos de cadena compartidos y devuelve el contenido del encabezado de columna mediante el Parse método . Si el contenido de la celda no está en el SharedStringTable objeto , devuelve el contenido de la celda.

// If the content of the first cell is stored as a shared string, get the text of the first cell
// from the SharedStringTablePart and return it. Otherwise, return the string value of the cell.
if (headCell.DataType is not null && headCell.DataType.Value == CellValues.SharedString && int.TryParse(headCell.CellValue?.Text, out int index))
{
    SharedStringTablePart shareStringPart = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
    SharedStringItem[] items = shareStringPart.SharedStringTable.Elements<SharedStringItem>().ToArray();

    return items[index].InnerText;
}
else
{
    return headCell.CellValue?.Text;
}

Código de ejemplo

A continuación se incluye el código de ejemplo completo en C# y Visual Basic.

static string? GetColumnHeading(string docName, string worksheetName, string cellName)
{
    // Open the document as read-only.
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(docName, false))
    {
        IEnumerable<Sheet>? sheets = document.WorkbookPart?.Workbook.Descendants<Sheet>().Where(s => s.Name == worksheetName);

        if (sheets is null || sheets.Count() == 0)
        {
            // The specified worksheet does not exist.
            return null;
        }

        string? id = sheets.First().Id;

        if (id is null)
        {
            // The worksheet does not have an ID.
            return null;
        }

        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart!.GetPartById(id);

        // Get the column name for the specified cell.
        string columnName = GetColumnName(cellName);

        // Get the cells in the specified column and order them by row.
        IEnumerable<Cell> cells = worksheetPart.Worksheet.Descendants<Cell>().Where(c => string.Compare(GetColumnName(c.CellReference?.Value), columnName, true) == 0)
            .OrderBy(r => GetRowIndex(r.CellReference) ?? 0);

        if (cells.Count() == 0)
        {
            // The specified column does not exist.
            return null;
        }

        // Get the first cell in the column.
        Cell headCell = cells.First();

        // If the content of the first cell is stored as a shared string, get the text of the first cell
        // from the SharedStringTablePart and return it. Otherwise, return the string value of the cell.
        if (headCell.DataType is not null && headCell.DataType.Value == CellValues.SharedString && int.TryParse(headCell.CellValue?.Text, out int index))
        {
            SharedStringTablePart shareStringPart = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
            SharedStringItem[] items = shareStringPart.SharedStringTable.Elements<SharedStringItem>().ToArray();

            return items[index].InnerText;
        }
        else
        {
            return headCell.CellValue?.Text;
        }
    }
}
// Given a cell name, parses the specified cell to get the column name.
static string GetColumnName(string? cellName)
{
    if (cellName is null)
    {
        return string.Empty;
    }

    // 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(cellName);

    return match.Value;
}

// Given a cell name, parses the specified cell to get the row index.
static uint? GetRowIndex(string? cellName)
{
    if (cellName is null)
    {
        return null;
    }

    // Create a regular expression to match the row index portion the cell name.
    Regex regex = new Regex(@"\d+");
    Match match = regex.Match(cellName);

    return uint.Parse(match.Value);
}

Recursos adicionales

Referencia de la biblioteca de clases del SDK de Open XML