Insertar texto en una celda de 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 insertar texto en una celda de una nueva hoja de cálculo de un documento de hoja de cálculo mediante programación.
Estructura básica de un documento spreadsheetML
La estructura de documento básica de un documento SpreadsheetML se compone de elementos Sheets y Sheet, que hacen referencia a las hojas de cálculo en el libro. Se crea un archivo XML independiente para cada hoja de cálculo. Por ejemplo, SpreadsheetML para un Workbook que tiene dos hojas de cálculo MySheet1 y MySheet2 se encuentra en el archivo Workbook.xml y se muestra en el siguiente ejemplo de código.
<?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>
Los archivos XML de hoja de cálculo contienen uno o varios elementos de nivel de bloque, como sheetData , que representa la tabla de celdas y contiene uno o varios elementos Row . Un elemento row contiene uno o más elementos Cell. Cada celda contiene un elemento CellValue que representa el valor de la celda. Por ejemplo, el SpreadsheetML para la primera hoja de cálculo del libro, que solo tiene el valor 100 en la celda A1, se encuentra en el archivo Sheet1.xml y se muestra en el siguiente ejemplo de código.
<?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 elementos SpreadsheetML . Puede encontrar estas clases en el espacio de nombres DocumentFormat.OpenXML.Spreadsheet. En la tabla siguiente se enumeran los nombres de las clases que corresponden a los elementos workbook, sheets, sheet, worksheet y sheetData.
Elemento de SpreadsheetML | Open XML SDK (clase) | Descripción |
---|---|---|
libro de trabajo | 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. |
hoja de cálculo | 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
Después de abrir el documento SpreadsheetDocument para editarlo, el código inserta un objeto Worksheet en blanco en un paquete de documento SpreadsheetDocument. A continuación, inserta un nuevo objeto Cell en la hoja de cálculo nueva e inserta el texto especificado en esa celda.
// Given a document name and text,
// inserts a new work sheet and writes the text to cell "A1" of the new worksheet.
static void InsertText(string docName, string text)
{
// Open the document for editing.
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
{
WorkbookPart workbookPart = spreadSheet.WorkbookPart ?? spreadSheet.AddWorkbookPart();
// Get the SharedStringTablePart. If it does not exist, create a new one.
SharedStringTablePart shareStringPart;
if (workbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = workbookPart.GetPartsOfType<SharedStringTablePart>().First();
}
else
{
shareStringPart = workbookPart.AddNewPart<SharedStringTablePart>();
}
// Insert the text into the SharedStringTablePart.
int index = InsertSharedStringItem(text, shareStringPart);
// Insert a new worksheet.
WorksheetPart worksheetPart = InsertWorksheet(workbookPart);
// Insert cell A1 into the new worksheet.
Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);
// Set the value of cell A1.
cell.CellValue = new CellValue(index.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
// Save the new worksheet.
worksheetPart.Worksheet.Save();
}
}
El código pasa en un parámetro que representa el texto para insertar en la celda y un parámetro que representa el objeto SharedStringTablePart para la hoja de cálculo. Si el objeto ShareStringTablePart no contiene un objeto SharedStringTable, el código crea uno. Si el texto ya existe en el objeto ShareStringTable, el código devuelve el índice para el objeto SharedStringItem que representa el texto. De lo contrario, se crea un nuevo objeto SharedStringItem que representa el texto.
El siguiente código comprueba si el texto especificado existe en el objeto SharedStringTablePart; si no existe, lo agrega.
// Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text
// and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
// If the part does not contain a SharedStringTable, create one.
if (shareStringPart.SharedStringTable is null)
{
shareStringPart.SharedStringTable = new SharedStringTable();
}
int i = 0;
// Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
{
if (item.InnerText == text)
{
return i;
}
i++;
}
// The text does not exist in the part. Create the SharedStringItem and return its index.
shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
shareStringPart.SharedStringTable.Save();
return i;
}
El código agrega un objeto nuevo WorksheetPart al objeto WorkbookPart mediante el método AddNewPart. Luego agrega un nuevo objeto Worksheet al objeto WorksheetPart y obtiene un ID exclusivo para la nueva hoja de cálculo seleccionando el objeto máximo SheetId usado en el documento de hoja de cálculo y agregando uno para crear un nuevo ID de hoja. Proporciona un nombre a la hoja de cálculo concatenando la palabra "Sheet" con el ID de hoja. Anexa el nuevo objeto Sheet a la colección Sheets.
El siguiente código inserta un nuevo objeto Worksheet mediante la adición de un nuevo objeto WorksheetPart al objetoWorkbookPart.
// Given a WorkbookPart, inserts a new worksheet.
static WorksheetPart InsertWorksheet(WorkbookPart workbookPart)
{
// Add a new worksheet part to the workbook.
WorksheetPart newWorksheetPart = workbookPart.AddNewPart<WorksheetPart>();
newWorksheetPart.Worksheet = new Worksheet(new SheetData());
newWorksheetPart.Worksheet.Save();
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>() ?? workbookPart.Workbook.AppendChild(new Sheets());
string relationshipId = workbookPart.GetIdOfPart(newWorksheetPart);
// Get a unique ID for the new sheet.
uint sheetId = 1;
if (sheets.Elements<Sheet>().Count() > 0)
{
sheetId = sheets.Elements<Sheet>().Select<Sheet, uint>(s =>
{
if (s.SheetId is not null && s.SheetId.HasValue)
{
return s.SheetId.Value;
}
return 0;
}).Max() + 1;
}
string sheetName = "Sheet" + sheetId;
// Append the new worksheet and associate it with the workbook.
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
sheets.Append(sheet);
workbookPart.Workbook.Save();
return newWorksheetPart;
}
Para insertar una celda en una hoja de cálculo, el código determina dónde se insertará la nueva celda de la columna mediante una iteración a través de los elementos de la fila para buscar la celda inmediatamente posterior a la fila especificada, en orden secuencial. Guarda esta fila en la variable refCell. Después inserta la nueva celda antes de la celda referenciada refCell con el método InsertBefore.
En el siguiente código, inserte un nuevo objeto Cell en un objeto Worksheet.
// Given a column name, a row index, and a WorksheetPart, inserts a cell into the worksheet.
// If the cell already exists, returns it.
static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
{
Worksheet worksheet = worksheetPart.Worksheet;
SheetData? sheetData = worksheet.GetFirstChild<SheetData>();
string cellReference = columnName + rowIndex;
// If the worksheet does not contain a row with the specified row index, insert one.
Row row;
if (sheetData?.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex).Count() != 0)
{
row = sheetData!.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex).First();
}
else
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
// If there is not a cell with the specified column name, insert one.
if (row.Elements<Cell>().Where(c => c.CellReference is not null && c.CellReference.Value == columnName + rowIndex).Count() > 0)
{
return row.Elements<Cell>().Where(c => c.CellReference is not null && c.CellReference.Value == cellReference).First();
}
else
{
// Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
Cell? refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference?.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
worksheet.Save();
return newCell;
}
}
Código de ejemplo
A continuación se incluye el código de ejemplo completo en C# y Visual Basic.
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;
// Given a document name and text,
// inserts a new work sheet and writes the text to cell "A1" of the new worksheet.
static void InsertText(string docName, string text)
{
// Open the document for editing.
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
{
WorkbookPart workbookPart = spreadSheet.WorkbookPart ?? spreadSheet.AddWorkbookPart();
// Get the SharedStringTablePart. If it does not exist, create a new one.
SharedStringTablePart shareStringPart;
if (workbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = workbookPart.GetPartsOfType<SharedStringTablePart>().First();
}
else
{
shareStringPart = workbookPart.AddNewPart<SharedStringTablePart>();
}
// Insert the text into the SharedStringTablePart.
int index = InsertSharedStringItem(text, shareStringPart);
// Insert a new worksheet.
WorksheetPart worksheetPart = InsertWorksheet(workbookPart);
// Insert cell A1 into the new worksheet.
Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);
// Set the value of cell A1.
cell.CellValue = new CellValue(index.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
// Save the new worksheet.
worksheetPart.Worksheet.Save();
}
}
// Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text
// and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
// If the part does not contain a SharedStringTable, create one.
if (shareStringPart.SharedStringTable is null)
{
shareStringPart.SharedStringTable = new SharedStringTable();
}
int i = 0;
// Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
{
if (item.InnerText == text)
{
return i;
}
i++;
}
// The text does not exist in the part. Create the SharedStringItem and return its index.
shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
shareStringPart.SharedStringTable.Save();
return i;
}
// Given a WorkbookPart, inserts a new worksheet.
static WorksheetPart InsertWorksheet(WorkbookPart workbookPart)
{
// Add a new worksheet part to the workbook.
WorksheetPart newWorksheetPart = workbookPart.AddNewPart<WorksheetPart>();
newWorksheetPart.Worksheet = new Worksheet(new SheetData());
newWorksheetPart.Worksheet.Save();
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>() ?? workbookPart.Workbook.AppendChild(new Sheets());
string relationshipId = workbookPart.GetIdOfPart(newWorksheetPart);
// Get a unique ID for the new sheet.
uint sheetId = 1;
if (sheets.Elements<Sheet>().Count() > 0)
{
sheetId = sheets.Elements<Sheet>().Select<Sheet, uint>(s =>
{
if (s.SheetId is not null && s.SheetId.HasValue)
{
return s.SheetId.Value;
}
return 0;
}).Max() + 1;
}
string sheetName = "Sheet" + sheetId;
// Append the new worksheet and associate it with the workbook.
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
sheets.Append(sheet);
workbookPart.Workbook.Save();
return newWorksheetPart;
}
// Given a column name, a row index, and a WorksheetPart, inserts a cell into the worksheet.
// If the cell already exists, returns it.
static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
{
Worksheet worksheet = worksheetPart.Worksheet;
SheetData? sheetData = worksheet.GetFirstChild<SheetData>();
string cellReference = columnName + rowIndex;
// If the worksheet does not contain a row with the specified row index, insert one.
Row row;
if (sheetData?.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex).Count() != 0)
{
row = sheetData!.Elements<Row>().Where(r => r.RowIndex is not null && r.RowIndex == rowIndex).First();
}
else
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
// If there is not a cell with the specified column name, insert one.
if (row.Elements<Cell>().Where(c => c.CellReference is not null && c.CellReference.Value == columnName + rowIndex).Count() > 0)
{
return row.Elements<Cell>().Where(c => c.CellReference is not null && c.CellReference.Value == cellReference).First();
}
else
{
// Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
Cell? refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference?.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
worksheet.Save();
return newCell;
}
}