OpenXML:excel在.xsls中发现了不可读的内容

时间:2014-09-25 07:57:49

标签: excel openxml

我在ASP.NET应用程序中使用OpenXML。以下是生成它的代码:

        MemoryStream ms = new System.IO.MemoryStream();
        SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(ms,             SpreadsheetDocumentType.Workbook);
        WorkbookPart workbookPart = spreadsheetDocument.AddWorkbookPart();
       workbookPart.Workbook = new Workbook();
       WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
       worksheetPart.Worksheet = new Worksheet();

        UInt32Value rowIndex = 0;
        SheetData sheetData = new SheetData();
        Row r1 = new Row() { RowIndex = rowIndex };

        Cell c1 = new Cell() { DataType = CellValues.String, CellValue=new CellValue("col1") };
        Cell c2 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col2") };
        Cell c3 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col3") };
        Cell c4 = new Cell() { DataType = CellValues.String, CellValue = new CellValue("col4") };
        r1.Append(new List<Cell>() { c1, c2, c3, c4 });
        rowIndex++;
        sheetData.Append(r1);

        foreach (Rezultat rez in rezultati)
        {
            Row r2 = new Row() { RowIndex = rowIndex };
            Cell c1 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.a) };
            Cell c2 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.b) };
            Cell c3 = new Cell() { DataType = CellValues.String, CellValue = new CellValue(rez.c) };
            Cell prolaz = new Cell() { DataType = CellValues.String };
            if (rez.d)
            {
                prolaz.CellValue = new CellValue("DA");
            }
            else
            {
                prolaz.CellValue = new CellValue("NE");
            }

            r2.Append(new List<Cell>() { c1,c2,c3,c4 });
            rowIndex++;
            sheetData.Append(r2);
        }

        worksheetPart.Worksheet.Append(sheetData);

        Sheets sheets = new Sheets();
        Sheet sheet = new Sheet();
        sheet.Name = "first";
        sheet.SheetId = 1;
        sheet.Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart);
        sheets.Append(sheet);
        spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(sheets);
        spreadsheetDocument.WorkbookPart.Workbook.Save();
        spreadsheetDocument.Close();


       string fileName = "testOpenXml.xlsx";
        Response.Clear();
        Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        Response.AddHeader("content-disposition", string.Format("attachment; filename={0}", fileName));
        ms.WriteTo(Response.OutputStream);
        ms.Close();
        Response.End();

当我下载它并尝试在excel中打开它时,我得到excel在excel中发现不可读的上下文的消息。我想我必须改变我如何生成excel的方式。我试了几个解决方案,有些给出了相同的错误,有些打开了excel,但没有数据。

3 个答案:

答案 0 :(得分:1)

如果单元格没有按顺序出现在文件中,您将收到此错误。

如果您在“如何:在电子表格文档中将文本插入单元格(Open XML SDK)”中使用 Microsoft的示例代码,您将看到有一个名为InsertCellInWorksheet的函数。此功能中有缺陷线:

if(string.Compare(cell.CellReference.Value,cellReference,true)&gt; 0)

如果您有超过26列,这将导致它们按如下方式排序:

A1 AA1 AB1 B1 C1 D1 E1 ....

结果是您将看到A列和AA上的数据。列B到Z将丢失,您将看到可怕的“Excel发现不可读的内容”消息。

你需要替换这个字符串。比较一个将AA1置于Z1之后的函数,或者...如果你知道你正在创建所有内容,则将其更改为if(false)。

答案 1 :(得分:0)

您要创建的是InlineString类型的单元格而不是String。

以下是实现您需要的部分内容的片段。希望您可以根据自己的需要进行修改。

SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(@"test.xlsx", SpreadsheetDocumentType.Workbook);

WorkbookPart workbookPart = spreadsheetDocument.AddWorkbookPart();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();

Row row = new Row { RowIndex = 1 };

Cell cell1 = new Cell { DataType = CellValues.InlineString };
InlineString inlineString1 = new InlineString();
Text text = new Text { Text = "col1" };
inlineString1.Append(text);
cell1.Append(inlineString1);

Cell cell2 = new Cell { DataType = CellValues.InlineString };
InlineString inlineString2 = new InlineString();
Text text2 = new Text { Text = "col2" };
inlineString2.Append(text2);
cell2.Append(inlineString2);

row.Append(new List<Cell>() { cell1, cell2 });

SheetData sheetData = new SheetData();
sheetData.Append(row);

Worksheet worksheet = new Worksheet();
worksheet.Append(sheetData);

worksheetPart.Worksheet = worksheet;
worksheetPart.Worksheet.Save();

Sheets sheets = new Sheets();
string relId = workbookPart.GetIdOfPart(worksheetPart);
Sheet sheet = new Sheet { Name = "Sheet1", SheetId = 1, Id = relId };
sheets.Append(sheet);

Workbook workbook = new Workbook();
workbook.Append(sheets);

spreadsheetDocument.WorkbookPart.Workbook = workbook;
spreadsheetDocument.WorkbookPart.Workbook.Save();
spreadsheetDocument.Close();

答案 2 :(得分:0)

我知道这是一个老问题,但我遇到了这个问题并在 MSDN 论坛中找到了解决方案。 SDK 示例包含根本不适用于 Z 列(例如 AA)的代码。 正如这里提到的,问题是使用字母顺序,AA1 会在 B1 之前,依此类推。解决它的方法是使字母 base-26 数字。在同一个 MSDN 论坛中,给出了解决方案。

首先创建一个 base-26 转换器:

//Hexavigesimal (Excel Column Name to Number) - Bijective
private int fromBase26(string colName)
{
    colName = colName.ToUpper();
    int decimalValue = 0;
    for (int i = 0; i < colName.Length; i++)
    {
        decimalValue *= 26;
        decimalValue += (colName[i] - 64);
    }
    return decimalValue;
}

然后,在方法中更改这一行以在工作表中插入一个单元格:

if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)

致:

if (fromBase26(Regex.Replace(cell.CellReference.Value, @"[\d-]", string.Empty)) > fromBase26(Regex.Replace(cellReference, @"[\d-]", string.Empty)))