4

I have a cell that contains the placeholder "$$value" in the Excel sheet, the thing is that I need to replace the placeholder's actual value using Open XML and save it as separate workbook.

Here is the code that I tried...it is not replacing the actual value and also I'm unable to save the workbook. I need to sort out this issue.

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

}
Lance Roberts
  • 22,383
  • 32
  • 112
  • 130
kart
  • 625
  • 3
  • 12
  • 21

2 Answers2

5

by default Excel stores strings in the global (1 per workbook) SharedStringTablePart. So, this is the one you need to target. However, the OpenXML format also allows inline text inside the WorksheetParts. hence, a complete solution needs to look there as well.

Here's a sample app (with some inline comments):

using DocumentFormat.OpenXml.Packaging;
using x = DocumentFormat.OpenXml.Spreadsheet;

class Program
{
private static readonly string placeHolder = "$$value";

static void Main()
{
    var templatePath = @"C:\Temp\template.xlsx";
    var resultPath = @"C:\Temp\result.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);
    }
}
mthierba
  • 5,587
  • 1
  • 27
  • 29
  • Hi ServiceGuy Thanks for your reply...the issue am facing from your code is i cant able to save using "new OpenSettings {AutoSave = true }" its getting reference issue for "OpenSetting"..is there any other way to save the workbook as another workbook leaving this as template.... – kart May 09 '11 at 14:06
  • @ kart: I updated the sample code to meet your requirements (load template and save to new file). Also, make sure to use the RTM of OpenXML SDK 2.0: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=c6e744e5-36e9-45f5-8d8c-331df206e0d0&displaylang=en – mthierba May 09 '11 at 15:18
  • @ServiceGuy:Thanks soo much for your guidence...while debuging i can able to find the text replacement in DoReplace function but those replaced text is not showing in the newly created excel file. for me i can't able to add OpenSetting "SpreadsheetDocument.Open(template, true, new OpenSettings { AutoSave = true })" third parameter is not allowing in the "SpreadsheetDocument.Open()" method its allowing only two parameters...still i can't able to replace the actual data in newly created file..its creating same as template file. – kart May 10 '11 at 09:19
  • @kart: You need to use the RTM of OpenXml SDK 2. The version number is **2.0.5022**. They've added the auto-save feature and that method overload relatively late. I'm pretty sure you're using an older version, and this is why it's not working for you, it would also explain why the new values don't show up in the new workbook. – mthierba May 10 '11 at 09:33
0

Solution:

 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
        }
BHUVANESH MOHANKUMAR
  • 2,747
  • 1
  • 33
  • 33