简体   繁体   English

OpenXML SDK 2.5不可读的内容

[英]OpenXML SDK 2.5 unreadable content

I am working on taking an existing Excel File which already has all of its formulas and formatting, I add data to the a sheet with a Table and when I then open that file in Excel I get the error 我正在研究已经拥有所有公式和格式的现有Excel文件,我将数据添加到带有表格的工作表中,然后当我在Excel中打开该文件时出现错误

"Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded. Removed Records: Cell information from /xl/worksheets/sheet6.xml part" “Excel已完成文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃。已移除的记录:来自/xl/worksheets/sheet6.xml部分的单元信息”

I then open a manually created file with the same content and it works just fine. 然后我打开一个具有相同内容的手动创建的文件,它工作得很好。 I also discovered the Open XML 2.5 Productivity Tool which when I run validation on the generated file it says no issues found. 我还发现了Open XML 2.5 Productivity Tool,当我对生成的文件运行验证时,它表示没有发现任何问题。

When I run a compare on the two files I see the Generated file looks like this. 当我在两个文件上运行比较时,我看到Generated文件看起来像这样。

        <x:c r="B462" t="inlineStr">
            <x:is>
                <x:t>1150828</x:t>
            </x:is>
        </x:c>

While the Manually created file has Cells that look like this. 虽然手动创建的文件具有看起来像这样的单元格。

       <c s="80" r="B462">
         <v>
           1150828
         </v>
       </c>

Obviously there is a difference here but I don't know how to correct it nor do I know if this difference is the actual cause of the error. 显然这里存在差异,但我不知道如何纠正它,也不知道这种差异是否是错误的实际原因。 but seeing as how everything else seems to look the same I don't know what else it could be. 但看到其他一切似乎看起来一样,我不知道它还能是什么。

Oh and couple more things this file is not working but I am able to use another file that does not contain a Table, when I incorporate a table the issue occurs so I at least know that much. 哦,还有更多的事情,这个文件不起作用,但我能够使用另一个不包含表的文件,当我合并一个表时问题发生所以我至少知道那么多。

Also if you're going to suggest that I use ClosedXML please don't. 此外,如果您打算建议我使用ClosedXML,请不要。 I have used it and it tends to leave off formatting at random for some reason that I cannot figure out hence why I have moved to OpenXML SDk 我已经使用过它,因为我无法弄清楚为什么我已经转移到OpenXML SDk,它往往会随意放弃格式化

Here is some of the C# Code 这是一些C#代码

 dt.Load(reader);
                            RowCount = dt.Rows.Count;
                            ColumnCount = dt.Columns.Count;

                                workbookPart = spreadDoc.WorkbookPart;
                                SheetDimension sheetDimension = new SheetDimension() { Reference = "A1:" + ColumnLetters[ColumnCount - 1] + (RowCount + 1) };

                                worksheetPart = Program.GetWorksheetPart(workbookPart, reportStep.ExcelSheetName);
                                worksheetPart.Worksheet.SheetDimension = sheetDimension;

                                SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
                                string relId = workbookPart.Workbook.Descendants<Sheet>().First(s => reportStep.ExcelSheetName.Equals(s.Name)).Id;

                                if (reportStep.ExcelTableExists)
                                {
                                    TableDefinitionPart tableDef = null;

                                    int looper = 0;
                                    foreach (WorksheetPart wsp in spreadDoc.WorkbookPart.WorksheetParts)
                                    {
                                        if (wsp.TableDefinitionParts.Where(tbl => tbl.Table.DisplayName.Value.Equals(reportStep.ExcelTableName)).Count() == 1)
                                        {
                                            tableDef = spreadDoc.WorkbookPart.WorksheetParts.ElementAt(looper).TableDefinitionParts.Where(tbl => tbl.Table.DisplayName.Value.Equals(reportStep.ExcelTableName)).FirstOrDefault();
                                            tableDef.Table.Reference.Value = "A1:" + (ColumnLetters[ColumnCount - 1] + (RowCount +1) ).ToString();
                                            tableDef.Table.AutoFilter.Reference.Value = "A1:" + (ColumnLetters[ColumnCount - 1] + (RowCount +1)).ToString();
                                           // tabledefinitionPart = Program.GetTablePart(wsp, reportStep.ExcelTableName, ColumnCount, RowCount);
                                        }
                                        looper++;
                                    }


                                }

                                sheetData = Chef.Program.ExportDataTable(dt, sheetData);
                                Sheet sheet = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == reportStep.ExcelSheetName);









public static TableDefinitionPart GetTablePart(WorksheetPart worksheet, string tablename, int columnCount, int rowCount)
    {
        uint CellRange = (uint)(columnCount);
        TableColumns tableColumns1 = new TableColumns() { Count = (UInt32Value)(CellRange) };

        var tableDefPart = worksheet.TableDefinitionParts.Where(tbl => tbl.Table.DisplayName.Value.Equals(tablename)).FirstOrDefault();
            //worksheet.WorksheetPart.TableDefinitionParts.AddNewPart<TableDefinitionPart>(tablename);
        var table = new Table() { HeaderRowCount = (uint)columnCount, Name = tablename, DisplayName = tablename, Reference = "A1:" + ColumnLetters[columnCount -1] + (rowCount + 1), TotalsRowShown = false };
        TableStyleInfo tableStyleInfo1 = new TableStyleInfo()
        {
            Name = "TableStyleMedium2",
            ShowFirstColumn = false,
            ShowLastColumn = false,
            ShowRowStripes = true,
            ShowColumnStripes = false
        };

        table.Append(tableStyleInfo1);
       // table.Append(tableColumns1);
        tableDefPart.Table = table;
        return tableDefPart;
    }

EDIT SECTION ADDING IN THE ADDITIONAL METHODS REQUESTED Updated 9/5/15 编辑部分在要求的其他方法中添加更新于2015年9月5日更新

I did remove the code that added the header values since they are already a part of the base template of the excel file. 我删除了添加标头值的代码,因为它们已经是excel文件基本模板的一部分。 also removed the specifying of the cell datatype to preserve what the template already had the cell datatype set to. 还删除了指定单元格数据类型以保留模板已经设置为单元格数据类型的内容。

       public static SheetData ExportDataTable2(System.Data.DataTable exportData, SheetData sheetData)
    {
        //loop through each data row  
        DataRow contentRow;
        int startRow = 2;
        for (int i = 0; i < exportData.Rows.Count; i++)
        {
            contentRow = exportData.Rows[i];
            sheetData.AppendChild(createContentRow(contentRow, i + startRow));
        }

        return sheetData;
    }


    private static Cell createTextCell(int columnIndex, int rowIndex, object cellValue)
    {
        Cell cell = new Cell();

       // cell.DataType = CellValues.Number;
        cell.CellReference = getColumnName(columnIndex) + rowIndex;
        cell.CellValue = new CellValue(cellValue.ToString());

        return cell;
    }

    private static Row createContentRow(DataRow dataRow, int rowIndex)
    {

        Row row = new Row
        {
            RowIndex = (UInt32)rowIndex
        };

        for (int i = 0; i < dataRow.Table.Columns.Count; i++)
        {
            Cell dataCell = createTextCell(i + 1, rowIndex, dataRow[i]);
          //  dataCell.DataType = CellValues.SharedString;
            row.AppendChild(dataCell);
        }

        return row;
    }

Well, it appears that you have used the following example OpenXML SDK 2.0: Export a DataTable to Excel as a base for your code. 好吧,您似乎使用了以下示例OpenXML SDK 2.0:将DataTable导出为Excel作为代码的基础。 Here is the original code for creating a cell: 以下是创建单元格的原始代码:

private Cell createTextCell(int columnIndex, int rowIndex, object cellValue)
{
    Cell cell = new Cell();

    cell.DataType = CellValues.InlineString;
    cell.CellReference = getColumnName(columnIndex) + rowIndex;
    InlineString inlineString = new InlineString();
    Text t = new Text();

    t.Text = cellValue.ToString();
    inlineString.AppendChild(t);
    cell.AppendChild(inlineString);

    return cell;
}

Your original code was exactly the same except the following line: 您的原始代码完全相同,但以下行除外:

cell.DataType = CellValues.String;

See the difference? 看到不同?

Then you have changed it to: 然后你把它改成了:

private static Cell createTextCell(int columnIndex, int rowIndex, object cellValue)
    {
        Cell cell = new Cell();

       // cell.DataType = CellValues.Number;
        cell.CellReference = getColumnName(columnIndex) + rowIndex;
        cell.CellValue = new CellValue(cellValue.ToString());

        return cell;
    }

Ok, the problem is that you don't set cell.DataType correctly. 好的,问题是你没有正确设置cell.DataType It needs to be in sync with the cell content, otherwise you'll get such an errors from Excel. 它需要与单元格内容同步,否则您将从Excel中获得此类错误。 In the former case you set content to inline string , but data type to String . 在前一种情况下,您将内容设置为inline string ,但将数据类型设置为String In the later - data type to Number (it doesn't matter that you have commented the line - Number is the default data type for cells) but the content is not always a number (the same function is used for the column headears - after all, it's called create Text Cell). 在后面 - 数据类型为Number (你注释了行没有关系 - Number是单元格的默认数据类型)但是内容并不总是一个数字(相同的函数用于列headears - 之后所有,它被称为创建文本单元格)。

In order to fix the problem, either use the original code from the example, or this code: 要解决此问题,请使用示例中的原始代码或此代码:

private static Cell createTextCell(int columnIndex, int rowIndex, object cellValue)
{
    Cell cell = new Cell();
    cell.DataType = CellValues.String;
    cell.CellReference = getColumnName(columnIndex) + rowIndex;
    cell.CellValue = new CellValue(cellValue.ToString());
    return cell;
}

Finally, if you need to store a shared string, number, date etc., read the documentation and set the appropriate properties. 最后,如果您需要存储共享字符串,数字,日期等,请阅读文档并设置相应的属性。 I would aggree that the OpenXml API is not very intuitive, but this is what we have. 我认为OpenXml API不是很直观,但这就是我们所拥有的。

EDIT: Based on your comments, seems like your real problem is not exactly the one in question. 编辑:根据您的意见,似乎您的真正问题不完全是问题。 Here is a high performance example of exporting DataTable with different data type columns: 以下是使用不同数据类型列导出DataTable高性能示例:

public static class ExcelExporter
{
    public static void ExportDataTable(DataTable table, SheetData data)
    {
        var cellFactory = new CellFactory[table.Columns.Count];
        for (int i = 0; i < table.Columns.Count; i++)
            cellFactory[i] = GetCellFactory(table.Columns[i].DataType);
        int rowIndex = 0;
        data.AppendChild(CreateHeaderRow(rowIndex++, table));
        for (int i = 0; i < table.Rows.Count; i++)
            data.AppendChild(CreateContentRow(rowIndex++, table.Rows[i], cellFactory));
    }
    private static Row CreateHeaderRow(int rowIndex, DataTable table)
    {
        var row = CreateRow(rowIndex);
        for (int i = 0; i < table.Columns.Count; i++)
        {
            var cell = CreateTextCell(i, rowIndex, table.Columns[i].ColumnName);
            row.AppendChild(cell);
        }
        return row;
    }
    private static Row CreateContentRow(int rowIndex, DataRow dataRow, CellFactory[] cellFactory)
    {
        var row = CreateRow(rowIndex);
        for (int i = 0; i < dataRow.Table.Columns.Count; i++)
        {
            var cell = cellFactory[i](i, rowIndex, dataRow[i]);
            row.AppendChild(cell);
        }
        return row;
    }
    private static Row CreateRow(int index) { return new Row { RowIndex = (uint)index + 1 }; }
    private delegate Cell CellFactory(int columnIndex, int rowIndex, object cellValue);
    private static CellFactory GetCellFactory(Type dataType)
    {
        CellFactory factory;
        return CellFactoryMap.TryGetValue(dataType, out factory) ? factory : TextCellFactory;
    }
    private static readonly CellFactory TextCellFactory = CreateTextCell;
    private static readonly CellFactory DateCellFactory = CreateDateCell;
    private static readonly CellFactory NumericCellFactory = CreateNumericCell;
    private static readonly CellFactory BooleanCellFactory = CreateBooleanCell;
    private static readonly Dictionary<Type, CellFactory> CellFactoryMap = new Dictionary<Type, CellFactory>
    {
        { typeof(bool), BooleanCellFactory },
        { typeof(DateTime), DateCellFactory },
        { typeof(byte), NumericCellFactory },
        { typeof(sbyte), NumericCellFactory },
        { typeof(short), NumericCellFactory },
        { typeof(ushort), NumericCellFactory },
        { typeof(int), NumericCellFactory },
        { typeof(uint), NumericCellFactory },
        { typeof(long), NumericCellFactory },
        { typeof(ulong), NumericCellFactory },
        { typeof(float), NumericCellFactory },
        { typeof(double), NumericCellFactory },
        { typeof(decimal), NumericCellFactory },
    };
    private static Cell CreateTextCell(int columnIndex, int rowIndex, object cellValue)
    {
        return CreateCell(CellValues.String, columnIndex, rowIndex, ToExcelValue(cellValue));
    }
    private static Cell CreateDateCell(int columnIndex, int rowIndex, object cellValue)
    {
        // NOTE: CellValues.Date is not supported in older Excel version.
        // In all Excel versions dates can be stored with CellValues.Number and a format style.
        // Since I have no styles, will export them just as text
        //var cell = CreateCell(CellValues.Number, columnIndex, rowIndex, ToExcelDate(cellValue));
        //cell.StyleIndex = ...;
        //return cell;
        return CreateCell(CellValues.String, columnIndex, rowIndex, 
            cellValue != null && cellValue != DBNull.Value ? ((DateTime)cellValue).ToShortDateString() : null);
    }
    private static Cell CreateNumericCell(int columnIndex, int rowIndex, object cellValue)
    {
        return CreateCell(CellValues.Number, columnIndex, rowIndex, ToExcelValue(cellValue));
    }
    private static Cell CreateBooleanCell(int columnIndex, int rowIndex, object cellValue)
    {
        // NOTE: CellValues.Boolean is not supported in older Excel version
        //return CreateCell(CellValues.Boolean, columnIndex, rowIndex, ToExcelValue(cellValue));
        return CreateCell(CellValues.String, columnIndex, rowIndex, ToExcelValue(cellValue));
    }
    private static Cell CreateCell(CellValues dataType, int columnIndex, int rowIndex, string cellValue)
    {
        var cell = new Cell();
        if (dataType != CellValues.Number) cell.DataType = dataType;
        cell.CellReference = GetColumnName(columnIndex) + (rowIndex + 1);
        cell.CellValue = new CellValue(cellValue ?? string.Empty);
        return cell;
    }
    private static string ToExcelValue(object value)
    {
        if (value == null || value == DBNull.Value) return null;
        return Convert.ToString(value, CultureInfo.InvariantCulture);
    }
    private static DateTime ExcelBaseDate = new DateTime(1900, 1, 1);
    private static string ToExcelDate(object value)
    {
        const int days29Feb1900 = 59;
        if (value == null || value == DBNull.Value) return null;
        var date = ((DateTime)value).Date;
        var days = (date - ExcelBaseDate).Days + 1;
        if (days >= days29Feb1900) days++;
        return days.ToString(CultureInfo.InvariantCulture);
    }
    private static string GetColumnName(int index) { return ColumnNameTable[index]; }
    private static readonly string[] ColumnNameTable = BuildColumnNameTable();
    private static string[] BuildColumnNameTable()
    {
        var table = new string[16384];
        var sb = new StringBuilder();
        for (int i = 0; i < table.Length; i++)
            table[i] = sb.BuildColumnName(i);
        return table;
    }
    private static string BuildColumnName(this StringBuilder sb, int index)
    {
        const int startLetter = 'A';
        const int letterCount = 'Z' - startLetter + 1;
        sb.Clear();
        while (true)
        {
            var letter = (char)(startLetter + (index % letterCount));
            sb.Insert(0, letter);
            if (index < letterCount) break;
            index = (index / letterCount) - 1;
        }
        return sb.ToString();
    }
}

The key point is, instead of checking the type of every value during the processing, prepare at the beginning a different create cell method for each column based on it's data type. 关键是,不是在处理过程中检查每个值的类型,而是在开始时为每列准备基于其数据类型的不同创建单元格方法。

I also had problems regarding invalid files working with the OpenXml Sdk. 关于使用OpenXml Sdk的无效文件,我也遇到了问题。 Have a look at the OpenXml Power Tools ; 看看OpenXml Power Tools ; they've solved all my issues :) Also you should switch to the OpenXml Sdk 2.6 to avoid problems with System.IO.Packaging . 他们已经解决了我所有的问题:)另外你应该切换到OpenXml Sdk 2.6以避免System.IO.Packaging问题。 I hope this helps! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM