使用共享字符串表 (Open XML SDK)

本主题讨论 Open XML SDK 2.5 SharedStringTable 类及其与 Open XML 文件格式 SpreadsheetML 架构的关系。 有关构成 SpreadsheetML 文档的各个部分和元素的整体结构的详细信息,请参阅 SpreadsheetML 文档的结构 (Open XML SDK)


SpreadsheetML 中的 SharedStringTable

ISO/IEC 29500 规范中的以下信息介绍了 SharedStringTable (<sst>) 元素。

此部分类型的实例包含在工作簿中的所有工作表上出现的每个唯一字符串的出现次数。

每个包应仅包含一个共享字符串表部分

此内容类型的部分的根元素应为 sst。

工作簿可能包含数以千计的包含字符串(非数值)数据的单元格。 而且,此数据非常可能在许多行或列中都是重复的。 实现在工作簿中共享的单个字符串表的目标是,通过只读取和写入重复的信息一次来在打开和保存文件时提高性能。

© ISO/IEC29500: 2008.

当电子表格包含同一字符串的多个实例时,共享字符串可优化空间需求。 包含业务或分析性数据的电子表格通常包含重复的字符串。 如果使用内联字符串标记存储这些字符串,则会在工作表中重复出现同一标记。 尽管这是有效方法,但它存在许多缺点。 首先,文件会由于多余的内容而需要更多磁盘空间。 其次,加载和保存时间也会延长。

为优化字符串在电子表格中的使用,SpreadsheetML 将字符串的单个实例存储在一个称为共享字符串表的表中。 然后单元格通过索引(而不是将值以内联方式存储在单元格值中)来引用该字符串。 Excel 在保存文件时,通常会创建一个共享字符串表。 但是,创建有效 SpreadsheetML 文件并不需要使用共享字符串表。 如果以编程方式创建电子表格文档,并且该电子表格包含少量字符串,或不包含任何重复的字符串,则通常从共享字符串表获得的优化在这些情形下可忽略不计。

共享字符串表是包中的一个单独部分。 每个工作簿只包含一个共享字符串表部分,其中包含可能会在一个或多个工作表中出现多次的字符串。

下表列出了在处理 SharedStringTable 类时常用的 Open XML SDK 2.5 类。

SpreadsheetML 元素 Open XML SDK 2.5 类
SharedStringItem
t Text

Open XML SDK 2.5 SharedStringTable 类

Open XML SDK 2.5SharedStringTable 类表示在 SpreadsheetML 文档的 Open XML 文件格式架构中定义的段落 (<sst>) 元素。 使用 SharedStringTable 类可操作 SpreadsheetML 文档中的各个 <sst> 元素。

共享字符串项类

SharedStringItem 类表示共享字符串项 (<si>) 元素,该元素表示共享字符串表中的单个字符串。

如果字符串是具有在单元格级别应用的格式的简单字符串,则共享字符串项包含用于表示该字符串的一个文本元素。 但是,如果单元格中的字符串更复杂(例如,如果字符串具有在字符级别应用的格式),则该字符串项包含用于共同表示该字符串的多个格式文本范围。

例如,以下 XML 代码是包含在单元格级别和字符级别设置格式的文本的工作表的共享字符串表。 前三个字符串("Cell A1"、"Cell B1"和"My Cell")来自在单元格级别设置格式的单元格,并且只有文本存储在共享字符串表中。 接下来的两个字符串("Cell A2"和"Cell B2")包含字符级别的格式设置。 单词“Cell”的格式不同于“A2”和“B2”,因此单元格的格式与共享字符串项中的文本一起存储,使用 RichTextRun (r>) < 和 RunProperties (<rPr>) 元素。 若要保留不同格式的文本之间的空白,请将文本 (<t>) 元素的 space 属性设置为等于保留。 有关格式文本范围和连续文本属性元素的详细信息,请参阅 ISO/IEC 29500 规范。

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <sst xmlns="https://schemas.openxmlformats.org/spreadsheetml/2006/main" count="6" uniqueCount="5">
        <si>
            <t>Cell A1</t>
        </si>
        <si>
            <t>Cell B1</t>
        </si>
        <si>
            <t>My Cell</t>
        </si>
        <si>
            <r>
                <rPr>
                    <sz val="11"/>
                    <color rgb="FFFF0000"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t>Cell</t>
            </r>
            <r>
                <rPr>
                    <sz val="11"/>
                    <color theme="1"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t xml:space="preserve"> </t>
            </r>
            <r>
                <rPr>
                    <b/>
                    <sz val="11"/>
                    <color theme="1"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t>A2</t>
            </r>
        </si>
        <si>
            <r>
                <rPr>
                    <sz val="11"/>
                    <color rgb="FF00B0F0"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t>Cell</t>
            </r>
            <r>
                <rPr>
                    <sz val="11"/>
                    <color theme="1"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t xml:space="preserve"> </t>
            </r>
            <r>
                <rPr>
                    <i/>
                    <sz val="11"/>
                    <color theme="1"/>
                    <rFont val="Calibri"/>
                    <family val="2"/>
                    <scheme val="minor"/>
                </rPr>
                <t>B2</t>
            </r>
        </si>
    </sst>

Text 类

Text 类表示文本 (<t>) 元素,该元素表示作为字符串的一部分显示的文本内容。

Open XML SDK 代码示例

以下代码采用 StringSharedStringTablePart,并验证指定文本是否存在于共享字符串表中。 如果文本不存在,则会将其作为共享字符串项添加到共享字符串表中。

有关如何使用 SharedStringTable 类以编程方式将文本插入单元格的详细信息,请参阅 如何:将文本插入电子表格文档中的单元格 (Open XML SDK)

    // Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text 
    // and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
    private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
    {
        // If the part does not contain a SharedStringTable, create one.
        if (shareStringPart.SharedStringTable == null)
        {
            shareStringPart.SharedStringTable = new SharedStringTable();
        }

        int i = 0;

        // Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
        foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
        {
            if (item.InnerText == text)
            {
                return i;
            }

            i++;
        }

        // The text does not exist in the part. Create the SharedStringItem and return its index.
        shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
        shareStringPart.SharedStringTable.Save();

        return i;
    }
    ' Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text 
    ' and inserts it into the SharedStringTablePart. If the item already exists, returns its index.
    Private Function InsertSharedStringItem(ByVal text As String, ByVal shareStringPart As SharedStringTablePart) As Integer
        ' If the part does not contain a SharedStringTable, create one.
        If (shareStringPart.SharedStringTable Is Nothing) Then
            shareStringPart.SharedStringTable = New SharedStringTable
        End If

        Dim i As Integer = 0

        ' Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
        For Each item As SharedStringItem In shareStringPart.SharedStringTable.Elements(Of SharedStringItem)()
            If (item.InnerText = text) Then
                Return i
            End If
            i = (i + 1)
        Next

        ' The text does not exist in the part. Create the SharedStringItem and return its index.
        shareStringPart.SharedStringTable.AppendChild(New SharedStringItem(New DocumentFormat.OpenXml.Spreadsheet.Text(text)))
        shareStringPart.SharedStringTable.Save()

        Return i
    End Function

生成的 SpreadsheetML

如果运行如何:在电子表格文档中的单元格内插入文本 (Open XML SDK)主题中的 Open XML SDK 2.5,并将"hello"一词插入单元格 A1,则以下 XML 会写入代码中引用的 SpreadsheetML 文档的 .zip 文件中的"sharedStrings.xml"文件。

    <?xml version="1.0" encoding="utf-8"?>
    <x:sst xmlns:x="https://schemas.openxmlformats.org/spreadsheetml/2006/main">
      <x:si>
        <x:t>hello</x:t>
      </x:si>
    </x:sst>

此外,以下 XML 会写入新工作表 XML 文件。

    <?xml version="1.0" encoding="utf-8"?>
    <x:worksheet xmlns:x="https://schemas.openxmlformats.org/spreadsheetml/2006/main">
      <x:sheetData>
        <x:row r="1">
          <x:c r="A1" t="s">
            <x:v>0</x:v>
          </x:c>
        </x:row>
      </x:sheetData>
    </x:worksheet>