使用带有OpenXML和SAX的模板

本文关键字:SAX OpenXML | 更新日期: 2023-09-27 18:10:29

我正在使用Open XML SDK中解析和读取大型Excel文件中提出的SAX方法,从数据表创建一个大型XLSX文件。我使用一个XLSX文件作为模板。

在那篇文章中描述的方法可以很好地替换现有的新工作表,但是我想复制模板中工作表的标题行(字符串值,格式等),而不是像原始代码那样使用数据表中的标题行。

我尝试了下面的代码,但是XLSX文件最终在标题行中没有文本-格式被复制,而不是文本。我在XML文件中查找了工作表,对我来说它看起来不错(引用sharedStrings.xml文件,其中仍然有字符串的定义)。但是,来自Open XML SDK 2.0生产力工具的反射代码显示了一个稍微奇怪的结果:单元格似乎没有文本值集:

cellValue1.Text = "";

尽管XML说:

<x:c r="A1" s="4" t="s">

OpenXmlReader使用的主要代码如下:

while (reader.Read())
{
    if (reader.ElementType == typeof(SheetData))
    {
        if (reader.IsEndElement)
            continue;
        // Write sheet element
        writer.WriteStartElement(new SheetData());
        // copy header row from template
        reader.Read();
        do
        {
            if (reader.IsStartElement)
            {
                writer.WriteStartElement(reader);
                        }
            else if (reader.IsEndElement)
            {
                writer.WriteEndElement();
            }
            reader.Read();
        } while (!(reader.ElementType == typeof(Row) && reader.IsEndElement));
        writer.WriteEndElement();
        // Write data rows
        foreach (DataRow dataRow in resultsTable.Rows)
        {
            // Write row element
            Row r = new Row();
            writer.WriteStartElement(r);
            foreach (DataColumn dataCol in resultsTable.Columns)
            {
                Cell c = new Cell();
                c.DataType = CellValues.String;
                CellValue v = new CellValue(dataRow[dataCol].ToString());
                c.Append(v);
                // Write cell element
                writer.WriteElement(c);
            }
            // End row
            writer.WriteEndElement();
        }
        // End sheet
        writer.WriteEndElement();
    }
    else
    {
        if (reader.IsStartElement)
        {
            writer.WriteStartElement(reader);
        }
        else if (reader.IsEndElement)
        {
            writer.WriteEndElement();
        }
    }
}

使用带有OpenXML和SAX的模板

线索是生产力工具显示了生成的工作表的标题单元格的空白值,而且模板中的验证公式也丢失了。这些都是文本,没有使用OpenXmlReader.Read()OpenXmlReader.WriteStartElement()的组合从模板工作表复制到新工作表。

当元素是OpenXmlLeafTextElement时,则OpenXmlReader.GetText()方法将返回文本-这适用于单元格中的文本值和公式。

工作代码如下所示:

while (openXmlReader.Read())
{
    if (openXmlReader.ElementType == typeof(SheetData))
    {
        if (openXmlReader.IsEndElement)
            continue;
        // write sheet element
        openXmlWriter.WriteStartElement(new SheetData());
        // read first row from template and copy into the new sheet
        openXmlReader.Read();
        do
        {
            if (openXmlReader.IsStartElement)
            {
                openXmlWriter.WriteStartElement(openXmlReader);
                
                // this bit is needed to get cell values
                if (openXmlReader.ElementType.IsSubclassOf(typeof(OpenXmlLeafTextElement)))
                {
                    openXmlWriter.WriteString(openXmlReader.GetText());
                }
            }
            else if (openXmlReader.IsEndElement)
            {
                openXmlWriter.WriteEndElement();
            }
            openXmlReader.Read();
        } while (!(openXmlReader.ElementType == typeof(Row) && openXmlReader.IsEndElement));
        openXmlWriter.WriteEndElement();
        // write data rows
        foreach (DataRow dataRow in resultsTable.Rows)
        {
            // write row element
            Row r = new Row();
            openXmlWriter.WriteStartElement(r);
            foreach (DataColumn dataCol in resultsTable.Columns)
            {
                Cell c = new Cell();
                c.DataType = CellValues.String;
                CellValue v = new CellValue(dataRow[dataCol].ToString());
                c.Append(v);
                // write cell element
                openXmlWriter.WriteElement(c);
            }
            // end row
            openXmlWriter.WriteEndElement();
        }
        // end sheet
        openXmlWriter.WriteEndElement();
    }
    else
    {
        if (openXmlReader.IsStartElement)
        {
            openXmlWriter.WriteStartElement(openXmlReader);
            // this bit is needed to get formulae and that kind of thing
            if (openXmlReader.ElementType.IsSubclassOf(typeof(OpenXmlLeafTextElement)))
            {
                openXmlWriter.WriteString(openXmlReader.GetText());
            }
        }
        else if (openXmlReader.IsEndElement)
        {
            openXmlWriter.WriteEndElement();
        }
    }
}