Импорт таблицы из WordprocessingML в SpreadsheetML

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

Решение

Чтобы импортировать таблицу из текстового документа в электронную таблицу, необходимо выполнить следующие действия:

  1. Создать в Word шаблон с элементом управления содержимым, который будет использоваться для разметки области импортируемой таблицы.
  2. Открыть документ Word с помощью пакета Open XML SDK.
  3. Открыть целевую книгу Excel, которая будет содержать импортированную таблицу, с помощью пакета Open XML SDK.
  4. Найти элемент управления содержимым, включающий таблицу Word, и получить доступ к табличному объекту.
  5. Преобразовать таблицу Word в электронную таблицу Excel. Под преобразованием понимается создание вручную таблицы Excel на основе данных таблицы Word.
  6. Добавить раздел определения таблицы в рабочую книгу Excel.
  7. Присвоить определению добавленной таблицы уникальное имя и идентификатор.
  8. Указать диапазон таблицы на основе вставляемых данных.
  9. Добавить сведения для заголовка столбцов в раздел определения таблицы.
  10. Добавить ссылку на стиль в определение таблицы.
  11. Сохранить изменения в рабочей книге Excel.

В моей демонстрации будет использоваться пакет SDK версии 2.

Чтобы более наглядно представить изложенный здесь материал, начнем работать со следующим документом Word и таблицей (следует отметить, что таблица содержится в элементе управления содержимым):

Кроме того, мы будем использовать пустую книгу Excel, содержащую лишь определение стиля для таблиц.

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

Код

Как описано в предыдущем разделе, для выполнения шагов 2 и 3 требуется открыть файлы Word и Excel. Для этого используется следующий фрагмент кода:

//Open Word document using (WordprocessingDocument myDoc = WordprocessingDocument.Open("tables.docx", true)) { MainDocumentPart mainPart = myDoc.MainDocumentPart; //Open spreadhseet using (SpreadsheetDocument mySpreadsheet = SpreadsheetDocument.Open("output.xlsx", true)) { WorkbookPart workbookPart = mySpreadsheet.WorkbookPart; //Import a specific table from the document into a specific sheet within the spreadsheet ImportWordTable(mainPart, "WorldPopulationTable", workbookPart, "Sheet1"); } }

Я создал универсальный метод ImportWordTable, выполняющий все остальные шаги представленного выше раздела "Решение". Следующий шаг — получение доступа к табличному объекту Word, находящемуся в элементе управления содержимым. Это можно осуществить с помощью следующего кода:

//Find the content control that contains the specific table SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>() .Where(s => s.SdtProperties.GetFirstChild<Alias>().Val.Value .Equals(sdtName)).First(); Table tbl = sdt.SdtContentBlock.GetFirstChild<Table>();

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

static Spreadsheet.SheetData ConvertWordTableToExcel(Table tbl) { //sheetdata contains data for table Spreadsheet.SheetData sheetdata = new Spreadsheet.SheetData(); //For every row in my Word table we need to create a row in Excel foreach (TableRow row in tbl.Descendants<TableRow>()) { numRows++; Spreadsheet.Row sheetRow = new Spreadsheet.Row(); //For every Word cell create an Excel cell foreach (TableCell cell in row.Descendants<TableCell>()) { Spreadsheet.Cell sheetCell = new Spreadsheet.Cell(); string textValue = cell.InnerText; double numValue; //Check to see if value is a number rather than a string //First row should be strings because I am going to create a table if ((numRows != 1) && (Double.TryParse(textValue, System.Globalization.NumberStyles.Any, null, out numValue))) { Spreadsheet.CellValue v = new Spreadsheet.CellValue(); textValue = numValue.ToString(); v.Text = textValue; sheetCell.Append(v); } else //value is a string { sheetCell.DataType = Spreadsheet.CellValues.InlineString; Spreadsheet.InlineString inlineString = new Spreadsheet.InlineString(); Spreadsheet.Text t = new Spreadsheet.Text(); t.Text = textValue; inlineString.Append(t); sheetCell.Append(inlineString); } //Need to keep track of column headers for the table //definitions part if (numRows == 1) colHeaders.Add(textValue); sheetRow.Append(sheetCell); }      sheetdata.Append(sheetRow); } return sheetdata; }

Представленный выше фрагмент кода создает для каждой строки и ячейки таблицы Word строку и ячейку в электронной таблице Excel. Ячейка электронной таблицы немного отличается от ячейки таблицы Word, поскольку в ячейке электронной таблицы содержится определение типа содержимого. В приведенном примере у нас два типа ячеек.

  1. Текст.
  2. Число.

Поскольку решение предполагает создание таблицы Excel, необходимо помнить еще о некоторых вещах. Во-первых, следует убедиться, что первая строка таблицы содержит только текстовые ячейки, поскольку она будет определена как строка заголовка. Во-вторых, необходимо отслеживать текст в строке заголовка, поскольку он будет повторно использован в разделе определений таблицы.

В конце этого шага мы создали допустимую электронную таблицу Excel, содержащую все данные из таблицы Word.

На этом работа могла бы быть закончена, но мы можем улучшить вывод, отформатировав данные в виде таблицы.

Вернувшись к шагу 6 в разделе "Решение", необходимо добавить ссылку на раздел определений таблицы на листе, содержащем данные. Ниже представлен фрагмент кода, создающий новый раздел определения таблицы и добавляющий ссылку на этот раздел с листа, содержащего табличные данные.

//Add the table definitions part to make the imported table look like a table TableDefinitionPart tableDefPart = worksheetPart.AddNewPart<TableDefinitionPart>(relId); //Reference the added table part Spreadsheet.TableParts tableParts = new Spreadsheet.TableParts(); Spreadsheet.TablePart tablePart = new Spreadsheet.TablePart(); tablePart.Id = relId; tableParts.Append(tablePart); worksheetPart.Worksheet.Append(tableParts);

Последняя серия шагов направлена на создание соответствующего кода XML в новом разделе определений таблицы. Чтобы все работало должным образом, каждое определение таблицы должно иметь уникальное имя, идентификатор, отображаемое имя и ссылку на диапазон данных. Эти задачи выполняются в следующем фрагменте кода:

int id = 1; tableDefPart.Table = new Spreadsheet.Table(); tableDefPart.Table.Id = 1; tableDefPart.Table.Name = "Table1"; tableDefPart.Table.DisplayName = "Table1"; char endCol = 'A'; //Note that this approach is good for columns up to Z //Excel can contain more columns, but 26 columns should //be good enough for this demo for (int i = 1; i < numCols; i++) endCol++; //Specify the range of the table string reference = "A1:" + endCol + numRows; tableDefPart.Table.Reference = reference;

Одним из преимуществ таблицы Excel перед таблицей Word является то, что таблица Excel позволяет фильтровать значения в пределах столбца. Эта функция довольно легко добавляется в таблицу с помощью следующего кода:

//Make sure the table has the ability to filter Spreadsheet.AutoFilter autoFilter = new Spreadsheet.AutoFilter(); autoFilter.Reference = reference; Spreadsheet.TableColumns tableColumns = new Spreadsheet.TableColumns(); tableColumns.Count = numCols;

Теперь добавим сведения для заголовка таблицы.

//Add the column headers to the table definition part foreach (string s in colHeaders) { Spreadsheet.TableColumn tableColumn = new Spreadsheet.TableColumn(); tableColumn.Id = (uint)id; tableColumn.Name = s; id++; tableColumns.Append(tableColumn); }

Почти готово! Теперь поработаем над внешним видом таблицы, применив стиль. После применения стиля можно объединить все необходимые элементы и сохранить изменения. Это можно выполнить, используя следующий код:

//Apply a nice table style (contained within my template) Spreadsheet.TableStyleInfo tableStyleInfo = new Spreadsheet.TableStyleInfo(); tableStyleInfo.Name = "TableStyleMedium9"; tableStyleInfo.ShowRowStripes = true; tableDefPart.Table.Append(autoFilter, tableColumns, tableStyleInfo); tableDefPart.Table.Save();

Заключение

Собрав вместе все показанные фрагменты и запустив итоговый код, мы получим рабочую книгу Excel, содержащую импортированную из документа Word таблицу.

Вот снимок экрана с полученной книгой (обратите внимание на возможность фильтрации):

Зияд Раджаби (Zeyad Rajabi)

Это локализованная запись блога. Исходную статью можно найти по адресу https://blogs.msdn.com/brian_jones/archive/2009/04/01/importing-a-table-from-wordprocessingml-to-spreadsheetml.aspx.