Импорт диаграмм из электронных таблиц в текстовые документы

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

Решение

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

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

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

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

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

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

Код

Как уже указывалось в разделе "Решение" выше, шаги 2–4 включают открытие документа Word, поиск элемента управления содержимым, в котором будет помещена импортированная диаграмма, и удаление замещающего содержимого этого элемента управления для подготовки к вставке диаграммы. Взгляните на фрагмент кода, в котором реализуется выполнение этих задач:

static void ImportChartFromSpreadsheet(string spreadsheetFileName, string wordFileName) { //Open Word document using (WordprocessingDocument myWordDoc = WordprocessingDocument.Open(wordFileName, true)) { //Find the content control that will contain the chart MainDocumentPart mainPart = myWordDoc.MainDocumentPart; SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>() .Where(s => a.SdtProperties.GetFirstChild<Alias>().Val.Value .Equals("Chart1")).First(); //Nuke the placeholder content of the content control Paragraph p = sdt.SdtContentBlock.GetFirstChild<Paragraph>(); p.RemoveAllChildren(); ... } }

Вы, наверно, заметили, что код, используемый для поиска соответствующего элемента управления содержимым, очень напоминает код, продемонстрированный в моей предыдущей записи для объединения документов Word. Чтобы подготовить элемент управления к вставке диаграммы, внутри него удаляются все дочерние элементы класса Paragraph.

Вместо работы с экземпляром класса Run и текстовыми элементами для данного элемента управления содержимым требуется создать экземпляр класса Run и встроенный объект-рисунок, необходимый для создания правильной ссылки на диаграмму. Эта задача выполняется с помощью следующего фрагмента кода:

//Create a new run that has an inline drawing object Run r = new Run(); p.Append(r); Drawing drawing = new Drawing(); r.Append(drawing); //These dimensions work perfectly for my template document wp.Inline inline = new wp.Inline( new wp.Extent() { Cx = 5486400, Cy = 3200400 });

Обратите внимание, что размеры импортируемой диаграммы в моем коде жестко заданы. Я ввел те размеры, которые, как мне кажется, лучше всего подходят к шаблону. Вы можете использовать любые размеры, соответствующие вашему документу. На данном этапе документ Word полностью готов для импорта диаграммы и ее вставки в элемент управления содержимым. Для импорта диаграммы необходимо получить доступ к соответствующему разделу диаграммы, а затем добавить этот раздел в документ Word. Эти задачи реализованы в следующем фрагменте кода:

//Open Excel spreadsheet using (SpreadsheetDocument mySpreadsheet = SpreadsheetDocument.Open(spreadsheetFileName, true)) { //Get all the appropriate parts WorkbookPart workbookPart = mySpreadsheet.WorkbookPart; WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById("rId1"); DrawingsPart drawingPart = worksheetPart.DrawingsPart; ChartPart chartPart = (ChartPart)drawingPart.GetPartById("rId1"); //Clone the chart part and add it to my Word document ChartPart importedChartPart = mainPart.AddPart<ChartPart>(chartPart); string relId = mainPart.GetIdOfPart(importedChartPart); ... }

Раздел диаграммы теперь входит в состав пакета документа Word. Нам осталось только правильно создать ссылку на этот раздел из встроенного объекта-рисунка, который находится внутри элемента управления содержимым. Чтобы наш код заработал, потребуется выполнить две задачи.

  1. Создать графическую ссылку на раздел диаграммы.
  2. Присвоить каждой диаграмме уникальные идентификатор и имя.

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

//The frame element contains information for the chart GraphicFrame frame = drawingPart.WorksheetDrawing.Descendants<GraphicFrame>().First(); string chartName = frame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.Name; //Clone this node so we can add it to my Word document d.Graphic clonedGraphic = (d.Graphic)frame.Graphic.CloneNode(true); ChartReference c = clonedGraphic.GraphicData.GetFirstChild<ChartReference>(); c.Id = relId;

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

static uint GetMaxDocPrId(MainDocumentPart mainPart) { uint max = 1; //Get max id value of docPr elements foreach (wp.DocProperties docPr in mainPart.Document.Descendants<wp.DocProperties>()) { uint id = docPr.Id; if (id > max) max = id; } return max; }

Мы почти закончили! Теперь остается только присвоить уникальные имя и идентификатор рисунку диаграммы и добавить все это во встроенный объект-рисунок. Эти задачи выполнены в следующем фрагменте кода:

//Give the chart a unique id and name wp.DocProperties docPr = new wp.DocProperties(); docPr.Name = chartName; docPr.Id = GetMaxDocPrId(mainPart) + 1; //add the chart data to the inline drawing object inline.Append(docPr, clonedGraphic); drawing.Append(inline);

Заключение

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

Взгляните на снимок экрана, на котором показан окончательный документ:

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

Это локализованная запись блога. Исходную статью можно найти по адресу https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx.