Partager via


Obtenir un en-tête de colonne dans un document de feuille de calcul

Cette rubrique montre comment utiliser les classes du Kit de développement logiciel (SDK) Open XML pour Office afin de récupérer un en-tête de colonne dans un document de feuille de calcul par programmation.

Structure de base d’un document spreadsheetML

La structure de base d’un document SpreadsheetML comprend les éléments Sheets et Sheet faisant référence aux feuilles de calcul dans le classeur. Un fichier XML distinct est créé pour chaque feuille de calcul. Par exemple, l’élément SpreadsheetML d’un élément Workbook qui contient deux feuilles de calcul nommées « MySheet1 » et « MySheet2 » se trouve dans le fichier Workbook.xml et apparaît dans l’exemple de code suivant.

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
    <workbook xmlns=https://schemas.openxmlformats.org/spreadsheetml/2006/main xmlns:r="https://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>

Les fichiers XML de feuille de calcul contiennent un ou plusieurs éléments de niveau bloc tels que sheetData représente la table de cellules et contient un ou plusieurs éléments Row . Un élément Row contient un ou plusieurs éléments Cell (cellule). Chaque cellule contient un élément CellValue qui représente la valeur de la cellule. Par exemple, le SpreadsheetML de la première feuille de calcul d'un classeur, qui possède uniquement la valeur 100 dans la cellule A1, se trouve dans le fichier Sheet1.xml et est illustré dans l'exemple de code suivant.

    <?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>

À l’aide du Kit de développement logiciel (SDK) Open XML, vous pouvez créer une structure de document et du contenu qui utilisent des classes fortement typées qui correspondent à des éléments SpreadsheetML . Vous pouvez trouver ces classes dans l'espace de noms DocumentFormat.OpenXML.Spreadsheet. La table suivante répertorie les noms des classes qui correspondent aux éléments workbook, sheets, sheet, worksheet et sheetData.

Élément SpreadsheetML Classe du Kit de développement logiciel (SDK) Open XML Description
workbook DocumentFormat.OpenXML.Spreadsheet.Workbook Élément racine du composant document principal.
sheets DocumentFormat.OpenXML.Spreadsheet.Sheets Conteneur des structures de niveau bloc comme les éléments de feuille, fileVersion et autres spécifiés par la norme ISO/IEC 29500.
sheet DocumentFormat.OpenXml.Spreadsheet.Sheet Feuille qui pointe vers un fichier de définition de feuille.
feuille de calcul Documentformat.openxml.spreadsheet. Feuilles de calcul Fichier de définition de feuille qui contient les données de feuille.
sheetData DocumentFormat.OpenXML.Spreadsheet.SheetData Tableau de cellules, regroupées par lignes.
row DocumentFormat.OpenXml.Spreadsheet.Row Ligne dans le tableau de cellules.
c DocumentFormat.OpenXml.Spreadsheet.Cell Cellule d'une ligne.
v DocumentFormat.OpenXml.Spreadsheet.CellValue Valeur d’une cellule.

Fonctionnement de l’exemple de code

Le code de cette procédure est constitué de trois méthodes (fonctions dans Visual Basic) : GetColumnHeading, GetColumnName et GetRowIndex. Les deux dernières méthodes sont appelées par la méthode GetColumnHeading.

La méthode GetColumnName accepte le nom de la cellule comme paramètre. Elle analyse le nom de la cellule pour obtenir le nom de la colonne en créant une expression régulière pour trouver le nom de la colonne dans le nom de la cellule. Pour en savoir plus sur les expressions régulières, consultez l’article Langage des expressions régulières - Aide-mémoire.

// 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;

La méthode GetRowIndex accepte le nom de la cellule comme paramètre. Elle analyse ce nom pour obtenir l'index de la ligne en créant une expression régulière pour trouver la partie index de ligne du nom de la cellule.

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

La méthode GetColumnHeading utilise trois paramètres, le chemin d'accès complet au fichier de tableur source, le nom de la feuille de calcul contenant la colonne spécifiée, et le nom d'une cellule dans la colonne dont vous souhaitez obtenir l'en-tête.

Le code obtient le nom de la colonne de la cellule spécifiée en appelant la méthode GetColumnName. Le code obtient également les cellules de la colonne et les ordonne par ligne en utilisant la méthode GetRowIndex.

// 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 la colonne spécifiée existe, il obtient la première cellule de la colonne à l'aide de la méthode IEnumerable(T).First. La première cellule contient l'en-tête. Sinon, la colonne spécifiée n’existe pas et la méthode retourne 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 le contenu de la cellule est stocké dans l’objet SharedStringTablePart, il obtient les éléments de chaîne partagée et renvoie le contenu de l’en-tête de colonne à l’aide de la méthode M:System.Int32.Parse(System.String). Si le contenu de la cellule n’est pas dans l’objet SharedStringTable, il renvoie le contenu de la cellule.

// 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;
}

Exemple de code

Voici un exemple de code complet en C# et Visual Basic.

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;


// Given a document name, a worksheet name, and a cell name, gets the column of the cell and returns
// the content of the first cell in that column.
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);
}