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


Многие читатели спрашивают, как можно импортировать диаграмму из документа одного типа в документ другого типа. В своей прошлой записи блога я показал, как поместить данные в таблицу для создания диаграммы. Сегодня я продемонстрирую процедуру импорта диаграммы из электронной таблицы в документ 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)

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


Skip to main content