OpenXML не может прочитать данные электронной таблицы после редактирования в Excel - PullRequest
0 голосов
/ 18 сентября 2018

Я использую OpenXML для экспорта некоторых данных перевода в электронную таблицу Excel, а затем импортирую ту же электронную таблицу обратно в мою программу.

Теперь это прекрасно работает, если я просто экспортирую и импортирую сразу, однакоЕсли я открою электронную таблицу в Excel и отредактирую ее или просто сохраню, моя программа не сможет прочитать данные, как если бы они были повреждены.Тем не менее, Excel просматривает его очень хорошо, если я снова открою его, поэтому файл на самом деле не поврежден.

Экспорт данных

using (SpreadsheetDocument document = SpreadsheetDocument.Create(saveLocation, SpreadsheetDocumentType.Workbook))
...

//Add a WorkbookPart to the document
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();

//Add a WorksheetPart to the WorkbookPart
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();

//Add style
WorkbookStylesPart stylePart = workbookPart.AddNewPart<WorkbookStylesPart>();
stylePart.Stylesheet = GenerateStylesheet();
stylePart.Stylesheet.Save();
...

SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
//Append some rows
...

worksheetPart.Worksheet.Save();

Чтение электронной таблицы

using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileStream, false))
        {
            WorkbookPart workbookPart = document.WorkbookPart;
            WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
            SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

            var headerRow = sheetData.Elements<Row>().FirstOrDefault();
            ...

            //All data here are numbers

Итак, вначале я подумал, что, возможно, Excel создает больше рабочих листов, и я просто ошибаюсь, полагая, что .First () даст мне правильный, но просмотр объекта во время отладки показывает, что данные каким-то образом верны.Очевидно, что здесь что-то не так, поэтому я решил посмотреть архивированное содержимое файла .xlsx.

Это сразу после того, как моя программа экспортировала и создала файл.Вы можете видеть, что в файле xml есть некоторые фактические данные (строки).

enter image description here

И это после того, как я открыл электронную таблицу в Excel и простосохранил его, не внося никаких изменений вообще.

enter image description here

Я не знаю, почему это происходит, если это как-то предполагалось.Я обнаружил, что OpenXML полон странных дизайнерских решений, но после прохождения этого лабиринта это первое, что действительно остановило мой прогресс.

Я строю на Netcore 2.0 на macOS и, очевидно, Excel также работаетна macOS.

Если бы кто-нибудь мог помочь мне решить эту проблему, я был бы очень рад.

1 Ответ

0 голосов
/ 20 сентября 2018

Существует два способа хранения строк в файле Excel;используя встроенную строку, как вы делали при создании, или, как указано в комментариях, используйте отдельный XML-файл с именем SharedStringTable.Случается, что в Excel используется последний подход, поэтому в каждой ячейке, содержащей непосредственно строку, вместо этого содержится индекс для записи в SharedStringTable.

К счастью, вы можете читать SharedStringTable, используя OpenXML, так же, как и любую другую частьдокумент.Например:

using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileStream, false))
    {
        WorkbookPart workbookPart = document.WorkbookPart;
        WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
        SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

        SharedStringTablePart stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();

        var headerRow = sheetData.Elements<Row>().FirstOrDefault();

        foreach (Cell c in headerRow.Elements<Cell>())
        {
            string cellText;

            if (c.DataType == CellValues.SharedString)
            {
                //the value will be a number which is an index into the shared strings table
                int index = int.Parse(c.CellValue.InnerText);
                cellText = stringTable.SharedStringTable.ElementAt(index).InnerText;
            }
            else
            {
                //just take the value from the cell (note this won't work for some types e.g. dates)
                cellText = c.CellValue.InnerText;
            }

            Console.WriteLine(cellText);
        }

    }
}

Для большого файла вы можете рассмотреть возможность кэширования общих строк, как обсуждалось в этом вопросе и ответе.

Как повысить производительность извлечениязначения из SharedStringTable в инструментах электронных таблиц OpenXml Excel?

...