web-dev-qa-db-fra.com

Open XML SDK 2.0 - comment mettre à jour une cellule dans une feuille de calcul?

Je souhaite mettre à jour une cellule dans une feuille de calcul utilisée par un graphique, à l'aide du Open XML SDK 2.0 (CTP). Tous les exemples de code que j'ai trouvés insèrent de nouvelles cellules. J'ai du mal à récupérer la bonne feuille de travail.

public static void InsertText(string docName, string text, uint rowIndex, 
  string columnName)
{
  // Open the document for editing.
  using (SpreadsheetDocument spreadSheet = 
    SpreadsheetDocument.Open(docName, true))
  {
    Workbook workBook = spreadSheet.WorkbookPart.Workbook;

    WorksheetPart worksheetPart = workBook.WorkbookPart.
      WorksheetParts.First();

    SheetData sheetData = worksheetPart.Worksheet.
      GetFirstChild<SheetData>();

    // 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 == rowIndex).Count() != 0)
      // At this point I am expecting a match for a row that exists
      // in sheet1 but I am not getting one

Lorsque je navigue dans l'arborescence de Visual Studio, je vois trois feuilles, mais aucune d'entre elles n'a d'enfants. Qu'est-ce que je rate?

35
cdonner

Voici le code de travail. Ceci est un prototype. Pour un plus grand nombre de modifications, il est possible d’ouvrir le document une seule fois. En outre, certains éléments codés en dur, tels que le nom de la feuille et le type de cellule, doivent être paramétrés avant que cela puisse s'appeler production-prêt . http://openxmldeveloper.org/forums/4005/ShowThread.aspx était très utile.

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Xml;
using System.IO;
using System.Diagnostics;

namespace OpenXMLWindowsApp
{
    public class OpenXMLWindowsApp
    {
        public void UpdateSheet()
        {
            UpdateCell("Chart.xlsx", "20", 2, "B");
            UpdateCell("Chart.xlsx", "80", 3, "B");
            UpdateCell("Chart.xlsx", "80", 2, "C");
            UpdateCell("Chart.xlsx", "20", 3, "C");

            ProcessStartInfo startInfo = new ProcessStartInfo("Chart.xlsx");
            startInfo.WindowStyle = ProcessWindowStyle.Normal;
            Process.Start(startInfo);
        }

        public static void UpdateCell(string docName, string text,
            uint rowIndex, string columnName)
        {
            // Open the document for editing.
            using (SpreadsheetDocument spreadSheet = 
                     SpreadsheetDocument.Open(docName, true))
            {
                WorksheetPart worksheetPart = 
                      GetWorksheetPartByName(spreadSheet, "Sheet1");

                if (worksheetPart != null)
                {
                    Cell cell = GetCell(worksheetPart.Worksheet, 
                                             columnName, rowIndex);

                    cell.CellValue = new CellValue(text);
                    cell.DataType = 
                        new EnumValue<CellValues>(CellValues.Number);

                    // Save the worksheet.
                    worksheetPart.Worksheet.Save();
                }
            }

        }

        private static WorksheetPart 
             GetWorksheetPartByName(SpreadsheetDocument document, 
             string sheetName)
        {
            IEnumerable<Sheet> sheets =
               document.WorkbookPart.Workbook.GetFirstChild<Sheets>().
               Elements<Sheet>().Where(s => s.Name == sheetName);

            if (sheets.Count() == 0)
            {
                // The specified worksheet does not exist.

                return null;
            }

            string relationshipId = sheets.First().Id.Value;
            WorksheetPart worksheetPart = (WorksheetPart)
                 document.WorkbookPart.GetPartById(relationshipId);
            return worksheetPart;

        }

        // Given a worksheet, a column name, and a row index, 
        // gets the cell at the specified column and 
        private static Cell GetCell(Worksheet worksheet, 
                  string columnName, uint rowIndex)
        {
            Row row = GetRow(worksheet, rowIndex);

            if (row == null)
                return null;

            return row.Elements<Cell>().Where(c => string.Compare
                   (c.CellReference.Value, columnName + 
                   rowIndex, true) == 0).First();
        }


        // Given a worksheet and a row index, return the row.
        private static Row GetRow(Worksheet worksheet, uint rowIndex)
        {
            return worksheet.GetFirstChild<SheetData>().
              Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
        } 
    }
}
67
cdonner

Je travaille avec Excel et je trouve que cette bibliothèque d’aides est très utile (j’ai créé mes propres aides pour Word, j’aurais économisé au moins deux semaines si j’étais au courant): http: //simpleooxml.codeplex.com/

Voici ce dont vous avez besoin pour mettre à jour la cellule (writer.PasteText (...)):

MemoryStream stream = SpreadsheetReader.Create();
SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true);
WorksheetPart worksheetPart = SpreadsheetReader.GetWorksheetPartByName(doc, "Sheet1");
WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart);

writer.PasteText("B2", "Hello World");

//Save to the memory stream
SpreadsheetWriter.Save(doc);

byte[] result = stream.ToArray();
FileStream file = new FileStream(@"D:\x1.xlsx", FileMode.Create);
file.Write(result, 0, result.Length);
file.Close();
6
pajics

Le code posté par @CDonner lève quelques exceptions, j'ai ajouté une partie du code qui s'occupera du code, qui jette une exception, la voici

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Xml;
using System.IO;
using System.Diagnostics;

namespace Application.Model{
public class TempCode
{
    public TempCode()
    {
        UpdateCell("E:/Visual Studio Code/Book1.xlsx", "120", 1, "A");
        UpdateCell("E:/Visual Studio Code/Book1.xlsx", "220", 2, "B");
        UpdateCell("E:/Visual Studio Code/Book1.xlsx", "320", 3, "C");
        UpdateCell("E:/Visual Studio Code/Book1.xlsx", "420", 4, "D");
        UpdateCell("E:/Visual Studio Code/Book1.xlsx", "520", 5, "E");

        ProcessStartInfo startInfo = new ProcessStartInfo("E:/Visual Studio Code/Book1.xlsx");
        startInfo.WindowStyle = ProcessWindowStyle.Normal;
        Process.Start(startInfo);



    }

    public static void UpdateCell(string docName, string text,uint rowIndex, string columnName){
        // Open the document for editing.
        using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
        {
            WorksheetPart worksheetPart = GetWorksheetPartByName(spreadSheet, "Sheet2");
            if (worksheetPart != null)
            {
                Cell cell = GetCell(worksheetPart.Worksheet, columnName, rowIndex);
                cell.CellValue = new CellValue(text);
                cell.DataType = new EnumValue<CellValues>(CellValues.Number);
                // Save the worksheet.
                worksheetPart.Worksheet.Save();
            }
        }

    }

    private static WorksheetPart GetWorksheetPartByName(SpreadsheetDocument document, string sheetName){
        IEnumerable<Sheet> sheets =document.WorkbookPart.Workbook.GetFirstChild<Sheets>().
                        Elements<Sheet>().Where(s => s.Name == sheetName);
        if (sheets.Count() == 0){
            return null;
        }
        string relationshipId = sheets.First().Id.Value;
        WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId);
        return worksheetPart;
    }


    private static Cell GetCell(Worksheet worksheet, string columnName, uint rowIndex)
    {
        Row row;
        string cellReference = columnName + rowIndex;
        if (worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
            row = worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault();
        else{
            row = new Row() { RowIndex = rowIndex };
            worksheet.Append(row);
        }

        if (row == null)
            return null;

        if (row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).Count() > 0) {
            return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
        }
        else{
            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, 
                StyleIndex = (UInt32Value)1U

            };
            row.InsertBefore(newCell, refCell);
            worksheet.Save();
            return newCell;
        }
    }
}

}

4
Ashwin

Ceci est du SDK 2.5, cependant, le code très utile se trouve ici: http://fczaja.blogspot.dk/2013/05/how-to-read-and-write-Excel-cells-with.html

Nécessaire pour faire une légère modification pour les valeurs de texte pour les ajouter à la SharedStringTablePart.

// 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.
private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
    // If the part does not contain a SharedStringTable, create one.
    if (shareStringPart.SharedStringTable == 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 Text(text)));
    shareStringPart.SharedStringTable.Save();

    return i;
}

Et utilisez-le comme ceci:

SharedStringTablePart shareStringPart = GetSharedStringTablePart(excelDoc);

// Insert the text into the SharedStringTablePart.
int index = InsertSharedStringItem(cellValue, shareStringPart);

// Set the value of cell A1.
cell.CellValue = new CellValue(index.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
2
Janis S.

J'ai apporté des modifications sur le code @AZ.

Tout d’abord, la fonction GetCell pose un problème lors de la sélection de la ligne en cours. Il suffit de changer:

if (worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)

au lieu de:

if (worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)

Et dans la section:

if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)

Si vous utilisez des colonnes supérieures à Z, la colonne (colonne AA, par exemple) ne fonctionnera pas correctement. Pour certains, j'utilise les numéros de colonne pour déterminer où insérer la cellule.

Pour cela, j'ai créé une fonction ColumnIndex, avec la conversion des lettres de colonnes en nombres:

private static int ColumnIndex(string reference)
    {
        int ci = 0;
        reference = reference.ToUpper();
        for (int ix = 0; ix < reference.Length && reference[ix] >= 'A'; ix++)
            ci = (ci * 26) + ((int)reference[ix] - 64);
        return ci;
    }

J'ai donc changé la fonction de comparaison de chaînes pour ceci:

string columnNew = new String(cellReference.Where(c => c != '-' && (c < '0' || c > '9')).ToArray());
            foreach (Cell cell in row.Elements<Cell>())
            {
                string columnBase = new String(cell.CellReference.Value.Where(c => c != '-' && (c < '0' || c > '9')).ToArray());

                if (ColumnIndex(columnBase) > ColumnIndex(columnNew))
                {
                    refCell = cell;
                    break;
                }
            }

Meilleures salutations.

0
zerala