From 929be3b9096e482d983321a573a53c004a7ae635 Mon Sep 17 00:00:00 2001 From: Tony Qu Date: Mon, 16 Mar 2026 13:45:54 +0800 Subject: [PATCH 1/3] Add SharedStringsTable.UseXmlReader switch --- .../NPOI.Benchmarks/LargeSSTBenchmark.cs | 12 ++++- ooxml/XSSF/Model/SharedStringsTable.cs | 51 +++++++++++-------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/benchmarks/NPOI.Benchmarks/LargeSSTBenchmark.cs b/benchmarks/NPOI.Benchmarks/LargeSSTBenchmark.cs index 95d74b60f..a5870248a 100644 --- a/benchmarks/NPOI.Benchmarks/LargeSSTBenchmark.cs +++ b/benchmarks/NPOI.Benchmarks/LargeSSTBenchmark.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Attributes; +using NPOI.XSSF.Model; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; @@ -46,8 +47,17 @@ public void XSSFWorkbookLargeSstOpenDispose() /// reduced in allocation compared to the old DOM path. /// [Benchmark] - public void XSSFWorkbookLargeSstLoadStrings() + public void XSSFWorkbookLargeSstLoadStringsViaXmlReader() { + SharedStringsTable.UseXmlReader = true; + using var workbook = new XSSFWorkbook(_largeFileWithSstPath, true); + // Force SST parse + _ = workbook.GetSharedStringSource().Count; + } + [Benchmark] + public void XSSFWorkbookLargeSstLoadStringsViaXmlDocument() + { + SharedStringsTable.UseXmlReader = false; using var workbook = new XSSFWorkbook(_largeFileWithSstPath, true); // Force SST parse _ = workbook.GetSharedStringSource().Count; diff --git a/ooxml/XSSF/Model/SharedStringsTable.cs b/ooxml/XSSF/Model/SharedStringsTable.cs index d9161a4db..204b04fb0 100644 --- a/ooxml/XSSF/Model/SharedStringsTable.cs +++ b/ooxml/XSSF/Model/SharedStringsTable.cs @@ -176,7 +176,10 @@ private void EnsureLoaded() { try { - ReadFromStream(stream); + if(UseXmlReader) + ReadFromStreamViaXmlReader(stream); + else + ReadFromStreamViaXmlDocument(stream); } catch (XmlException e) { @@ -218,7 +221,33 @@ private void EnsureStmapBuilt() /// private const int TextReadBufferSize = 1024; - private void ReadFromStream(Stream stream) + public static bool UseXmlReader = false; + + public void ReadFromStreamViaXmlDocument(Stream is1) + { + try + { + int cnt = 0; + XmlDocument xml = ConvertStreamToXml(is1); + _sstDoc = SstDocument.Parse(xml, NamespaceManager); + CT_Sst sst = _sstDoc.GetSst(); + count = (int)sst.count; + uniqueCount = (int)sst.uniqueCount; + foreach (CT_Rst st in sst.si) + { + string key = GetKey(st); + if (key != null && !stmap.ContainsKey(key)) + stmap.Add(key, cnt); + strings.Add(st); + cnt++; + } + } + catch (XmlException e) + { + throw new IOException("unable to parse shared strings table", e); + } + } + private void ReadFromStreamViaXmlReader(Stream stream) { _sstDoc = new SstDocument(); _sstDoc.AddNewSst(); @@ -509,24 +538,6 @@ private static CT_Color ParseColorAttributes(XmlReader reader) return color; } - /// - /// Read shared strings from a stream. Kept for backward compatibility; internally - /// delegates to the streaming parser. - /// - public void ReadFrom(Stream is1) - { - try - { - ReadFromStream(is1); - _loaded = true; - _stmapBuilt = false; - } - catch (XmlException e) - { - throw new IOException("unable to parse shared strings table", e); - } - } - private static String GetKey(CT_Rst st) { return st.XmlText; From 92302344765e7b0d1418e299fb129855eec49410 Mon Sep 17 00:00:00 2001 From: Tony Qu Date: Mon, 16 Mar 2026 13:51:22 +0800 Subject: [PATCH 2/3] remove stmap build logic to align with new XmlReader logic --- ooxml/XSSF/Model/SharedStringsTable.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/ooxml/XSSF/Model/SharedStringsTable.cs b/ooxml/XSSF/Model/SharedStringsTable.cs index 204b04fb0..b869ef0eb 100644 --- a/ooxml/XSSF/Model/SharedStringsTable.cs +++ b/ooxml/XSSF/Model/SharedStringsTable.cs @@ -227,20 +227,11 @@ public void ReadFromStreamViaXmlDocument(Stream is1) { try { - int cnt = 0; XmlDocument xml = ConvertStreamToXml(is1); _sstDoc = SstDocument.Parse(xml, NamespaceManager); CT_Sst sst = _sstDoc.GetSst(); - count = (int)sst.count; - uniqueCount = (int)sst.uniqueCount; - foreach (CT_Rst st in sst.si) - { - string key = GetKey(st); - if (key != null && !stmap.ContainsKey(key)) - stmap.Add(key, cnt); - strings.Add(st); - cnt++; - } + count = sst.count; + uniqueCount = sst.uniqueCount; } catch (XmlException e) { From f151ea60efa532713b542eead93dd4893e31d20a Mon Sep 17 00:00:00 2001 From: Tony Qu Date: Sun, 22 Mar 2026 01:56:22 +0800 Subject: [PATCH 3/3] make SharedStringTable.UseXmlReader internal only --- ooxml/XSSF/Model/SharedStringsTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooxml/XSSF/Model/SharedStringsTable.cs b/ooxml/XSSF/Model/SharedStringsTable.cs index b869ef0eb..893945821 100644 --- a/ooxml/XSSF/Model/SharedStringsTable.cs +++ b/ooxml/XSSF/Model/SharedStringsTable.cs @@ -221,7 +221,7 @@ private void EnsureStmapBuilt() /// private const int TextReadBufferSize = 1024; - public static bool UseXmlReader = false; + internal static bool UseXmlReader { get; set; } = true; public void ReadFromStreamViaXmlDocument(Stream is1) {