Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to Write Shared String Table Part using OpenXmlWriter #1755

Closed
benjaminki opened this issue Jul 23, 2024 · 0 comments · Fixed by #1760
Closed

Unable to Write Shared String Table Part using OpenXmlWriter #1755

benjaminki opened this issue Jul 23, 2024 · 0 comments · Fixed by #1760

Comments

@benjaminki
Copy link

Describe the bug
When using the OpenXmlWriter to write the Shared String Table part, the resulting sharedStrings.xml document saved to disk does not contain any string items. I've created a very simple script that creates an excel document, a default sheet, and tries to updated the shared string table to contain one entry. (The next step would be to use OpenXmlWriter to write one row with one cell with shared string value)

To Reproduce

CancellationToken ct = CancellationToken.None;

void Main()
{
	using (FileStream destinationFileStream = File.Create(@"C:\temp\Simple_Doc_Using_OpenXml_Sax_SharedString.xlsx", 1024 * 16))
	using (var destinationSpreadsheetDocument = CreateNewSpreadsheet(destinationFileStream))
	{
		var newWorksheetPart = CreateWorksheet(destinationSpreadsheetDocument, "Sheet1");
		
		// Use XmlWriter to write the SharedString contents - SAX model - writing start to end
		using (var sharedStringTablePartWriter = OpenXmlWriter.Create(destinationSpreadsheetDocument.WorkbookPart.SharedStringTablePart))
		{
			sharedStringTablePartWriter.WriteStartDocument();
			sharedStringTablePartWriter.WriteStartElement(new SharedStringTable());

			sharedStringTablePartWriter.WriteElement(new SharedStringItem(new Text("Is Current")));

			// End tag for SharedStringTable element.
			sharedStringTablePartWriter.WriteEndElement();
		}
	}
}

SpreadsheetDocument CreateNewSpreadsheet(Stream stream)
{
	SpreadsheetDocument newDoc = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook);

	// Add a WorkbookPart to the document.
	WorkbookPart workbookPart = newDoc.AddWorkbookPart();
	//workbookPart.Workbook = new Workbook();

	// Add Sheets section to the Workbook.
	//Sheets sheets = newDoc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());

	// Add a SharedStringTablePart to the WorkbookPart.
	SharedStringTablePart sharedStringTablePart = workbookPart.AddNewPart<SharedStringTablePart>();
	sharedStringTablePart.SharedStringTable = new SharedStringTable();

	// Add a WorkbookStylesPart to the WorkbookPart, and create default styles.
	WorkbookStylesPart workStylePart = workbookPart.AddNewPart<WorkbookStylesPart>();
	workStylePart.Stylesheet = new Stylesheet();

	workStylePart.Stylesheet.Borders = new Borders() { Count = 1 };
	workStylePart.Stylesheet.Borders.AppendChild(new Border { LeftBorder = new LeftBorder(), RightBorder = new RightBorder(), TopBorder = new TopBorder(), BottomBorder = new BottomBorder(), DiagonalBorder = new DiagonalBorder() });

	workStylePart.Stylesheet.CellFormats = new CellFormats() { Count = 1 };
	workStylePart.Stylesheet.CellFormats.AppendChild(new CellFormat { NumberFormatId = 0, FontId = 0, FillId = 0, BorderId = 0 }); // empty one for index 0, seems to be required

	workStylePart.Stylesheet.CellStyleFormats = new CellStyleFormats() { Count = 1 };
	workStylePart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat { NumberFormatId = 0, FontId = 0, FillId = 0, BorderId = 0, FormatId = 0 });

	workStylePart.Stylesheet.DifferentialFormats = new DifferentialFormats() { Count = 0 };

	workStylePart.Stylesheet.Fills = new Fills() { Count = 2 };
	workStylePart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.None } }); // required, reserved by Excel
	workStylePart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.Gray125 } }); // required, reserved by Excel

	workStylePart.Stylesheet.Fonts = new Fonts() { Count = 1 };
	workStylePart.Stylesheet.Fonts.AppendChild(
		new Font()
		{
			FontName = new FontName() { Val = "Calibri" },
			FontSize = new FontSize() { Val = 11 }
		});

	workStylePart.Stylesheet.TableStyles = new TableStyles() { Count = 0, DefaultTableStyle = "TableStyleMedium2", DefaultPivotStyle = "PivotStyleLight16" };

	return newDoc;
}

WorksheetPart CreateWorksheet(SpreadsheetDocument doc, string sheetName)
{
	var newWorksheetPart = doc.WorkbookPart.AddNewPart<WorksheetPart>();
	
	// Updating the workbook part done via DOM since we just want to append a sheet to the end, and the workbook xml is not so large, loading it into memory won't be a significan cost.
	if (doc.WorkbookPart.Workbook == null)
	{
		doc.WorkbookPart.Workbook = new Workbook();
	}
	
	if (doc.WorkbookPart.Workbook.Sheets == null)
	{
		doc.WorkbookPart.Workbook.Sheets = new Sheets();
	}

	Sheet sheet = new Sheet() { Id = doc.WorkbookPart.GetIdOfPart(newWorksheetPart), SheetId = Convert.ToUInt32(doc.WorkbookPart.Workbook.Sheets.Count() + 1), Name = sheetName };
	doc.WorkbookPart.Workbook.Sheets.Append(sheet);

	// Saves data in Workbook DOM tree back to the WorkbookPart.
	doc.WorkbookPart.Workbook.Save();

	return newWorksheetPart;
}

Steps to reproduce the behavior:

  1. Execute Main method
  2. Rename xlsx file to .zip file
  3. Extract contents of zip file
  4. Review contents of sharedStrings.xml in text editor. Observe issue, that no Shared String has been added.

Observed behavior
The sharedStrings.xml is minimal, containing only the xml root tag and shared string table tag, with no children.

Expected behavior
The sharedStrings.xml should have xml defining a shared string item with child Text item with value "Is Current"

Desktop (please complete the following information):

  • OS: Windows
  • Office version [e.g. 16.0.15427.20178]
  • .NET Target: (e.g. .NET Framework, .NET Core, UWP, Xamarin...)
  • DocumentFormat.OpenXml Version 3.0.2

Additional context
I need to use the SAX model using OpenXmlWriter to write the content, and not the DOM model, as I'm working with large data sets across multiple spreadsheets and doing merge/copy operations, and need to be mindful of memory usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant