2009-02-09 57 views
30

我想使用Open XML SDK 2.0(CT​​P)更新图表使用的电子表格中的单元格。我找到的所有代码示例都插入了新的单元格。我正在努力检索正确的工作表。Open XML SDK 2.0 - 如何更新电子表格中的单元格?

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 

当我在Visual Studio中导航树时,我看到三张表,但他们都没有任何孩子。我错过了什么?

+1

我正在取得进展。有一件事让我难过,那就是所有的例子都假定WorksheetParts.First()让你获得“Sheet1”工作表。事实并非如此,它相当于返回workbook.xml中的第一个元素。当我有它的工作时,我会发布代码。 – cdonner 2009-02-09 14:46:53

+0

尝试WorksheetParts 。First()。它将得到第一个表单类型的元素。 – 2014-06-03 18:00:25

回答

60

以下是工作代码。这是一个原型。对于更多的更改,可能只会打开一次文档。此外,还有一些硬编码的东西,如工作表名称和单元格类型,在可称为生产就绪之前必须进行参数化。 http://openxmldeveloper.org/forums/4005/ShowThread.aspx非常有帮助。

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(); 
     } 
    } 
} 
+1

感谢您的工作代码......我很容易就能适应我的情况。你是对的,大多数例子都创建了新的工作簿/工作表和单元格。我只想更新一些现有的单元格。 – 2009-10-11 12:39:26

+2

当我使用你的(优秀的)示例代码时,我得到了预期的结果,但是当我在Excel 2010中打开XLSX文件(尚未在2007年进行测试)时,我收到警告,说明某些内容不太正确(Excel发现无法读取的内容)并提供修复它。 我不知道这是否与此代码没有插入文本到字符串表中第一次。 我将如何修改此代码以消除警告? – 2010-09-03 21:38:38

6

我一直在使用Excel,发现这个助手库是有很大的帮助(我已经创建了自己的助手的话,将有可能挽救至少2周,如果我意识到这一点): http://simpleooxml.codeplex.com/

这是什么是需要更新单元(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(); 
3

发表@CDonner的代码抛出一些例外,我添加了一些代码的那将处理代码,这会抛出一个例外,在这里我t是

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

}

1

这是SDK 2.5,虽然,但是,在这里发现了非常有用的代码:http://fczaja.blogspot.dk/2013/05/how-to-read-and-write-excel-cells-with.html

需要做文本值略作修改,将其添加到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; 
} 

而且使用这样的:

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

我做了@AZ代码一些变化。

首先,GetCell函数在选择当前行时出现问题。只要改变:

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

代替:

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

,并在段:

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

如果使用上面列z支柱(如AA列,例如)将不好好工作。对此,我使用列号确定插入单元格的位置。

对于这一点,我创建了一个功能ColumnIndex,以转换列字母数字:

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

所以我改变了字符串比较功能此:

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

问候。

相关问题