1###############################################################################
2#
3# SharedStrings - A class for writing the Excel XLSX sharedStrings file.
4#
5# SPDX-License-Identifier: BSD-2-Clause
6#
7# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org
8#
9
10# Package imports.
11from . import xmlwriter
12from .utility import _preserve_whitespace
13
14
15class SharedStrings(xmlwriter.XMLwriter):
16 """
17 A class for writing the Excel XLSX sharedStrings file.
18
19 """
20
21 ###########################################################################
22 #
23 # Public API.
24 #
25 ###########################################################################
26
27 def __init__(self):
28 """
29 Constructor.
30
31 """
32
33 super().__init__()
34
35 self.string_table = None
36
37 ###########################################################################
38 #
39 # Private API.
40 #
41 ###########################################################################
42
43 def _assemble_xml_file(self):
44 # Assemble and write the XML file.
45
46 # Write the XML declaration.
47 self._xml_declaration()
48
49 # Write the sst element.
50 self._write_sst()
51
52 # Write the sst strings.
53 self._write_sst_strings()
54
55 # Close the sst tag.
56 self._xml_end_tag("sst")
57
58 # Close the file.
59 self._xml_close()
60
61 ###########################################################################
62 #
63 # XML methods.
64 #
65 ###########################################################################
66
67 def _write_sst(self):
68 # Write the <sst> element.
69 xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
70
71 attributes = [
72 ("xmlns", xmlns),
73 ("count", self.string_table.count),
74 ("uniqueCount", self.string_table.unique_count),
75 ]
76
77 self._xml_start_tag("sst", attributes)
78
79 def _write_sst_strings(self):
80 # Write the sst string elements.
81
82 for string in self.string_table.string_array:
83 self._write_si(string)
84
85 def _write_si(self, string):
86 # Write the <si> element.
87 attributes = []
88
89 # Convert control character to a _xHHHH_ escape.
90 string = self._escape_control_characters(string)
91
92 # Add attribute to preserve leading or trailing whitespace.
93 if _preserve_whitespace(string):
94 attributes.append(("xml:space", "preserve"))
95
96 # Write any rich strings without further tags.
97 if string.startswith("<r>") and string.endswith("</r>"):
98 self._xml_rich_si_element(string)
99 else:
100 self._xml_si_element(string, attributes)
101
102
103# A metadata class to store Excel strings between worksheets.
104class SharedStringTable:
105 """
106 A class to track Excel shared strings between worksheets.
107
108 """
109
110 def __init__(self):
111 self.count = 0
112 self.unique_count = 0
113 self.string_table = {}
114 self.string_array = []
115
116 def _get_shared_string_index(self, string):
117 """ " Get the index of the string in the Shared String table."""
118 if string not in self.string_table:
119 # String isn't already stored in the table so add it.
120 index = self.unique_count
121 self.string_table[string] = index
122 self.count += 1
123 self.unique_count += 1
124 return index
125
126 # String exists in the table.
127 index = self.string_table[string]
128 self.count += 1
129 return index
130
131 def _get_shared_string(self, index):
132 """ " Get a shared string from the index."""
133 return self.string_array[index]
134
135 def _sort_string_data(self):
136 """ " Sort the shared string data and convert from dict to list."""
137 self.string_array = sorted(self.string_table, key=self.string_table.__getitem__)
138 self.string_table = {}