OpenXML Excel当值在SharedStringTable中时如何更改单元格的值

我正在寻找一种安全和有效的方式来更新单元格的值可能在SharedStringTable(这似乎是由MS Excel创build的任何电子表格的情况下)的值。

顾名思义,SharedStringTable包含可能在多个单元格中使用的string。

所以只要在string表中find这个项目并且更新这个值并不是要走的路,因为它也可能被其他单元使用。

据我所知,必须做到以下几点:

  1. 检查单元格是否使用string表

  2. 如果是这样,检查新的string是否已经存在,在这种情况下只使用它(记住,如果其他单元格不再使用旧string,请删除该项目)!

  3. 如果不是,请检查电子表格中的任何其他单元格是否具有旧string的项目

  4. 如果是这样,用新的string创build新的项目,并引用它

  5. 如果不是,只需用新string更新现有的项目

使用OpenXML SDK有没有更简单的解决scheme?

另外考虑一个人可能不仅要更新一个单元,而是要为几个单元设置新的(不同的)值。 所以我们可能会在循环中调用更新单元格方法…

正如你所看到的共享string表的更新操作真的让开发人员忙碌。

在我的经验中,共享string表不会增加任何性能和文件大小的经济性。 OpenXml格式压缩在一个包装容器内,所以即使你有大量复制的string,也不会影响文件的大小。

Microsoft Excel将所有内容写入共享string表,即使没有重复。

我build议只是在修改文档之前将所有内容转换为InlineStrings ,并且进一步的操作变得尽可能简单。

你可以简单地把它写成InlineStrings ,这将是一个function相同的文档文件。

当文件被编辑时,Microsoft Excel会将其转换回共享string表,但是谁在乎。

我会build议在未来版本的标准中删除共享的string表格function,除非有一些合理的基准。

首先承担这一点。 似乎为我的具体情况工作。 但是,必须有可能改进,甚至更好,完全不同:

 private static void UpdateCell(SharedStringTable sharedStringTable, Dictionary<string, SheetData> sheetDatas, string sheetName, string cellReference, string text) { Cell cell = sheetDatas[sheetName].Descendants<Cell>() .FirstOrDefault(c => c.CellReference.Value == cellReference); if (cell == null) return; if (cell.DataType == null || cell.DataType != CellValues.SharedString) { cell.RemoveAllChildren(); cell.AppendChild(new InlineString(new Text { Text = text })); cell.DataType = CellValues.InlineString; return; } // Cell is refering to string table. Check if new text is already in string table, if so use it. IEnumerable<SharedStringItem> sharedStringItems = sharedStringTable.Elements<SharedStringItem>(); int i = 0; foreach (SharedStringItem sharedStringItem in sharedStringItems) { if (sharedStringItem.InnerText == text) { cell.CellValue = new CellValue(i.ToString()); // TODO: Should clean up, ie remove item with old text from string table if it is no longer in use. return; } i++; } // New text not in string table. Check if any other cells in the Workbook referes to item with old text. foreach (SheetData sheetData in sheetDatas.Values) { var cells = sheetData.Descendants<Cell>(); foreach (Cell cell0 in cells) { if (cell0.Equals(cell)) continue; if (cell0.DataType != null && cell0.DataType == CellValues.SharedString && cell0.CellValue.InnerText == cell.CellValue.InnerText) { // Other cells refer to item with old text so we cannot update it. Add new item. sharedStringTable.AppendChild(new SharedStringItem(new Text(text))); cell.CellValue.Text = (i).ToString(); return; } } } // No other cells refered to old item. Update it. sharedStringItems.ElementAt(int.Parse(cell.CellValue.InnerText)).Text = new Text(text); } 

….

 private static void DoIt(string filePath) { using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(filePath, true)) { SharedStringTable sharedStringTable = spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>() .First().SharedStringTable; Dictionary<string, SheetData> sheetDatas = new Dictionary<string, SheetData>(); foreach (var sheet in spreadSheet.WorkbookPart.Workbook.Descendants<Sheet>()) { SheetData sheetData = (spreadSheet.WorkbookPart.GetPartById(sheet.Id) as WorksheetPart) .Worksheet.GetFirstChild<SheetData>(); sheetDatas.Add(sheet.Name, sheetData); } UpdateCell(sharedStringTable, sheetDatas, "Sheet1", "A2", "Mjau"); } } 

警告:不要使用上述的,它与一个特定的电子表格。 如果在其他情况下使用它,很可能不会处理这些事情。 这是我第一次尝试OpenXML电子表格。 结束了乔治·波列沃伊的build议。 更容易,似乎没有不良的副作用(这就是说,当操纵电子表格可能会在您的控制之外进行编辑时,还有一百万个其他问题需要处理)