Импорт диаграмм из электронных таблиц в текстовые документы
Многие читатели спрашивают, как можно импортировать диаграмму из документа одного типа в документ другого типа. В своей прошлой записи блога я показал, как поместить данные в таблицу для создания диаграммы. Сегодня я продемонстрирую процедуру импорта диаграммы из электронной таблицы в документ Word.
Решение
Для импорта диаграммы из электронной таблицы в документ Word потребуется выполнить следующие действия:
- Создать в программе Word шаблон, содержащий элемент управления содержимым, который будет определять область для вставки диаграммы.
- Открыть созданный документ Word с помощью пакета Open XML SDK и получить доступ к главному разделу документа.
- Найти элемент управления содержимым, в котором планируется разместить диаграмму.
- Удалить все замещающее содержимое в этом элементе управления.
- Создать новый экземпляр класса Run и встроенный объект-рисунок для вставки в данный элемент управления содержимым. Этот встроенный объект-рисунок будет содержать ссылочные сведения для диаграммы.
- Открыть электронную таблицу с помощью пакета Open XML SDK и получить доступ к соответствующим разделам (к главному разделу книги, разделам электронной таблицы, рисунка и диаграммы).
- Скопировать раздел диаграммы и добавить его в документ Word.
- Скопировать графические сведения о диаграмме (имя диаграммы и ее свойства) из электронной таблицы и добавить их в документ Word.
- Присвоить диаграмме в документе Word уникальные имя и идентификатор.
- Добавить данные диаграммы в элемент управления содержимым.
- Сохранить изменения документа 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. Нам осталось только правильно создать ссылку на этот раздел из встроенного объекта-рисунка, который находится внутри элемента управления содержимым. Чтобы наш код заработал, потребуется выполнить две задачи.
- Создать графическую ссылку на раздел диаграммы.
- Присвоить каждой диаграмме уникальные идентификатор и имя.
Выполнение первой задачи не составляет никакого труда, поскольку можно повторно использовать те же графические объекты из электронной таблицы. Однако потребуется убедиться, что отношение ссылается на соответствующий раздел диаграммы в документе 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.