#c# #excel #openxml-sdk
#c# #excel #openxml-sdk
Вопрос:
У меня есть ячейка, которая содержит заполнитель «$$value» на листе Excel, дело в том, что мне нужно заменить фактическое значение заполнителя с помощью Open XML и сохранить его как отдельную книгу.
Вот код, который я tried…it не заменяет фактическое значение, а также я не могу сохранить рабочую книгу. Мне нужно разобраться в этом вопросе.
WorksheetPart worksheetPart = (WorksheetPart)myWorkbook.WorkbookPart.GetPartById(sheet.Id);
DocumentFormat.OpenXml.Spreadsheet.Worksheet worksheet = worksheetPart.Worksheet;
string _txt1 = "$$value";
if (_txt1.Contains("$$"))
{
worksheet.InnerText.Replace(_txt1, "test");
}
Ответ №1:
по умолчанию Excel хранит строки в глобальном формате (по 1 на книгу) SharedStringTablePart
. Итак, это то, на что вам нужно ориентироваться. Однако формат OpenXML также допускает встроенный текст внутри частей рабочего листа. следовательно, полное решение также должно выглядеть там.
Вот пример приложения (с некоторыми встроенными комментариями):
using DocumentFormat.OpenXml.Packaging;
using x = DocumentFormat.OpenXml.Spreadsheet;
class Program
{
private static readonly string placeHolder = "$$value";
static void Main()
{
var templatePath = @"C:Temptemplate.xlsx";
var resultPath = @"C:Tempresult.xlsx";
string replacementText = "test";
using (Stream xlsxStream = new MemoryStream())
{
// Read template from disk
using (var fileStream = File.OpenRead(templatePath))
fileStream.CopyTo(xlsxStream);
// Do replacements
ProcessTemplate(xlsxStream, replacementText);
// Reset stream to beginning
xlsxStream.Seek(0L, SeekOrigin.Begin);
// Write results back to disk
using (var resultFile = File.Create(resultPath))
xlsxStream.CopyTo(resultFile);
}
}
private static void ProcessTemplate(Stream template, string replacementText)
{
using (var workbook = SpreadsheetDocument.Open(template, true, new OpenSettings { AutoSave = true }))
{
// Replace shared strings
SharedStringTablePart sharedStringsPart = workbook.WorkbookPart.SharedStringTablePart;
IEnumerable<x.Text> sharedStringTextElements = sharedStringsPart.SharedStringTable.Descendants<x.Text>();
DoReplace(sharedStringTextElements, replacementText);
// Replace inline strings
IEnumerable<WorksheetPart> worksheetParts = workbook.GetPartsOfType<WorksheetPart>();
foreach (var worksheet in worksheetParts)
{
var allTextElements = worksheet.Worksheet.Descendants<x.Text>();
DoReplace(allTextElements, replacementText);
}
} // AutoSave enabled
}
private static void DoReplace(IEnumerable<x.Text> textElements, string replacementText)
{
foreach (var text in textElements)
{
if (text.Text.Contains(placeHolder))
text.Text = text.Text.Replace(placeHolder, replacementText);
}
}
Комментарии:
1. Привет, ServiceGuy, спасибо за ваш ответ… проблема, с которой я сталкиваюсь в вашем коде, заключается в том, что я не могу сохранить, используя «новые настройки OpenSettings {автосохранение = true }», это проблема с получением ссылки на «OpenSetting» .. есть ли какой-либо другой способ сохранить книгу как другую книгу, оставив это в качестве шаблона….
2. @ kart: Я обновил пример кода, чтобы он соответствовал вашим требованиям (загрузите шаблон и сохраните в новый файл). Кроме того, обязательно используйте RTM из OpenXML SDK 2.0: microsoft.com/downloads/en /…
3. @ServiceGuy: Большое спасибо за ваше руководство… во время отладки я могу найти замену текста в функции DoReplace, но этот замененный текст не отображается во вновь созданном файле Excel. для меня я не могу добавить OpenSetting «SpreadsheetDocument. Открыть (шаблон, true, новые настройки OpenSettings { автосохранение = true })» третий параметр не разрешен в «SpreadsheetDocument. Метод Open() «допускает только два параметра … тем не менее, я не могу заменить фактические данные во вновь созданном файле .. его создание совпадает с файлом шаблона.
4. @kart: Вам нужно использовать RTM из OpenXML SDK 2. Номер версии — 2.0.5022 . Они добавили функцию автоматического сохранения, и этот метод перегрузился относительно поздно. Я почти уверен, что вы используете более старую версию, и именно поэтому она у вас не работает, это также объясняет, почему новые значения не отображаются в новой книге.
Ответ №2:
Решение:
private static void ProcessTemplate(Stream template, Dictionary<string,string> toReplace)
{
using (var workbook = SpreadsheetDocument.Open(template, true, new OpenSettings { AutoSave = true }))
{
workbook.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
workbook.WorkbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;
//Replace SheetNames
foreach (Sheet sheet in workbook.WorkbookPart.Workbook.Sheets)
foreach (var key in toReplace.Keys)
sheet.Name.Value = sheet.Name.Value.Replace(key, toReplace[key]);
foreach (WorksheetPart wsheetpart in workbook.WorkbookPart.WorksheetParts)
foreach (SheetData sheetd in wsheetpart.Worksheet.Descendants<x.SheetData>())
foreach (Row r in wsheetpart.Worksheet.Descendants<x.Row>())
foreach (Cell c in r.Descendants<x.Cell>())
if (c.CellFormula != null)
{
foreach (var key in toReplace.Keys)
c.CellFormula.Text = c.CellFormula.Text.Replace(key, toReplace[key]);
}
// Replace shared strings
SharedStringTablePart sharedStringsPart = workbook.WorkbookPart.SharedStringTablePart;
IEnumerable<x.Text> sharedStringTextElements = sharedStringsPart.SharedStringTable.Descendants<x.Text>();
for(int i =0;i<toReplace.Keys.Count; i )
DoReplace(sharedStringTextElements, toReplace);
IEnumerable<x.Formula> sharedStringTextElementsF = sharedStringsPart.SharedStringTable.Descendants<x.Formula>();
for (int i = 0; i < toReplace.Keys.Count; i )
DoReplaceFormula(sharedStringTextElementsF, toReplace);
// Replace inline strings
IEnumerable<WorksheetPart> worksheetParts = workbook.GetPartsOfType<WorksheetPart>();
foreach (var worksheet in worksheetParts)
{
var allTextElements = worksheet.Worksheet.Descendants<x.Text>();
DoReplace(allTextElements, toReplace);
var allTextElements2 = worksheet.Worksheet.Descendants<x.Formula>();
DoReplaceFormula(allTextElements2, toReplace);
}
} // AutoSave enabled
}