Использование объектной модели Open XML для операций над файлами Excel 2007 и PowerPoint 2007 (часть 1 из 2)
Аннотация. Предварительная версия пакета SDK Microsoft для форматов Open XML — это библиотека доступа к файлам формата Open XML. В этой первой из двух запланированных статей описан код, который с помощью объектной модели Open XML позволяет получать доступ и производить операции над файлами Microsoft Office Excel 2007 и Microsoft Office PowerPoint 2007. (12 печатных страниц).
Фрэнк Райс (Frank Rice), корпорация Майкрософт
Август 2007 г.
Продукты и технологии: Microsoft Office Excel 2007, Microsoft Office PowerPoint 2007
Содержание
Обзор
Удаление комментариев в книгах по имени пользователя
Удаление листов
Обнаружение в книгах скрытых столбцов и строк
Экспорт диаграмм из книг
Получение списка скрытых книг
Получение значения ячейки в книге
Заключение
Дополнительные материалы
Смотрите вторую часть: Использование объектной модели Open XML для операций над файлами Excel 2007 и PowerPoint 2007 (часть 2 из 2).
Обзор
В системе Microsoft Office 2007 впервые использован новый, основанный на XML формат файлов, называемый «форматы Open XML». Microsoft Office Word 2007, Microsoft Office Excel 2007 и Microsoft Office PowerPoint 2007 (русские версии) используют этот формат в качестве формата своих файлов по умолчанию. Форматы Open XML полезны, поскольку являются открытыми стандартами и основываются на хорошо известных технологиях: ZIP и XML. Microsoft предоставляет библиотеку доступа к таким файлам в пространстве имен System.IO.Packaging.NET Framework 3.0 предварительной версии пакета SDK Microsoft для форматов Open XML. Объектная модель Open XML основана на API System.IO.Packaging. Она предоставляет набор классов со строгим контролем типов для операций над документами Open XML. Пакет SDK упрощает задачу управления пакетами Open XML. Решение многих задачи, которые часто встречаются разработчикам, включено в объектную модель Open XML. Благодаря этой модели всего несколькими строками кода можно выполнять сложные операции.
Примечание. |
---|
Дополнительные примеры операций над файлами формата Open XML, а также ссылки на каждый член класса, содержащийся в объектной модели Open XML для 2007 Office System: Пакет SDK Microsoft SDK для форматов Open XML. |
Спецификация Open Package Convention определяет набор файлов XML, в которых находится содержимое и определяются отношения всех частей документа, сохранённых в одном пакете. Файлы документов программ выпуска 2007 Microsoft Office, поддерживающих формат Open XML, состоят из комбинаций таких пакетов. Обсуждаемая в этой статье объектная модель Open XML позволяет создавать пакеты и управлять файлами, составляющими пакеты. В этой серии статей я опишу код, с помощью которого можно осуществлять доступ и выполнять операции над пакетами Open XML в Excel 2007 и PowerPoint 2007.
Удаление комментариев в книгах по имени пользователя
Следующий код удаляет из документа комментарии по указанному имени пользователя.
Visual Basic
Public Sub XLDeleteCommentsByUser(ByVal fileName As String, ByVal userName As String) Const commentsSchema As String = "https://schemas.openxmlformats.org/spreadsheetml/2006/main" Dim doc As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, True) ' Manage namespaces to perform XML XPath queries. Dim nt As NameTable = New NameTable Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt) nsManager.AddNamespace("sh", commentsSchema) For Each part As WorksheetPart In doc.WorkbookPart.WorksheetParts If (Not (part.WorksheetCommentsPart) Is Nothing) Then Dim commentDoc As XmlDocument = New XmlDocument commentDoc.Load(part.WorksheetCommentsPart.GetStream) Dim searchString As String = String.Format("//sh:authors/sh:author[text()='{0}']", userName) Dim node As XmlNode = commentDoc.SelectSingleNode(searchString, nsManager) If (Not (node) Is Nothing) Then Dim nodes As XmlNodeList = node.SelectNodes("preceding-sibling::sh:author", nsManager) Dim authorID As Integer = nodes.CountC#FakePre-9e051270848a487da16761e76f16e868-7f8200c6b8a942bc9dc40a9d41c76aefDim commentListNode As XmlNode = commentDoc.SelectSingleNode("sh:comments/sh:commentList", nsManager) If (Not (commentListNode) Is Nothing) Then searchString = String.Format("./sh:comment[@authorId='{0}']", authorID) Dim comments As XmlNodeList = commentListNode.SelectNodes(searchString, nsManager) For Each commentNode As System.Xml.XmlNode In comments commentListNode.RemoveChild(commentNode) Next End If End If ' Save the comment XML back to its part. commentDoc.Save(part.WorksheetCommentsPart.GetStream(FileMode.Create)) End If
Next End Sub
В эту процедуру передаются два параметра: полный путь к файлу и имя пользователя человека, чьи комментарии необходимо удалить. Затем с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию с квалификатором sh.
Затем в процедуре проверяется наличие комментариев в пакете. Содержимое комментариев загружается в постоянно находящийся в памяти документ XML. Затем в книге производится поиск заданного имени пользователя с помощью выражений Xpath sh:authors/sh:author. Если имя пользователя найдено, нужно узнать порядковый номер имени пользователя. Потом возвращается индекс выбранного узла. Для этого нужно сосчитать количество узлов, предшествующих данному, получая ссылки на все узлы.
В конце работы обновленный поток с комментариями сохраняется в часть комментариев.
Удаление листов
Следующий код удаляет книгу из документа электронной таблицы.
Visual Basic
Public Function XLDeleteSheet(ByVal fileName As String, ByVal sheetToDelete As String) As Boolean Dim returnValue As Boolean = False ' Open the package with read/write access. Dim xlDoc As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, True) Dim doc As XmlDocument = New XmlDocument doc.Load(xlDoc.WorkbookPart.GetStream) Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable) nsManager.AddNamespace("d", doc.DocumentElement.NamespaceURI) Dim searchString As String = String.Format("//d:sheet[@name='{0}']", sheetToDelete) Dim node As XmlNode = doc.SelectSingleNode(searchString, nsManager) If (Not (node) Is Nothing) Then Dim relationAttribute As XmlAttribute = node.Attributes("r:id") If (Not (relationAttribute) Is Nothing) Then Dim relId As String = relationAttribute.Value xlDoc.WorkbookPart.DeletePart(relId) node.ParentNode.RemoveChild(node) doc.Save(xlDoc.WorkbookPart.GetStream(FileMode.Create)) returnValue = True End If End If Return returnValue End FunctionC#FakePre-5b9e78900def4d038c67f298bcf89165-7f268e467943420f85fa627e74ba8c78
В эту процедуру передаются два параметра: полный путь к книге и имя листа, который надо удалить. Затем с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML. Потом содержимое книги загружается в документ XML DOM. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию с квалификатором d. Найти указанный лист в документе можно, используя атрибут «имя» узла //d:sheet.
Для каждого найденного узла, если такие узлы существуют, извлекается код связи и лист, соответствующий этому коду, удаляется.
В конце обновленные исправления SpreadsheetML сохраняются назад, в главную часть книги.
Обнаружение в книгах скрытых столбцов и строк
По заданному имени книги и листа данный код возвращает список номеров скрытых строк или скрытых столбцов.
Visual Basic
Public Function XLDetectHiddenRowsOrCols(ByVal fileName As String, ByVal sheetName As String, ByVal detectRows As Boolean) As List(Of Integer) Const worksheetSchema As String = "https://schemas.openxmlformats.org/spreadsheetml/2006/main" ' Set up the return value list. Dim itemList As List(Of Integer) = New System.Collections.Generic.List(Of Integer) Dim xlDoc As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, False) ' Load the contents of the workbook. Dim doc As XmlDocument = New XmlDocument doc.Load(xlDoc.WorkbookPart.GetStream) ' Create a namespace manager, so you can search. ' Add a prefix for the default namespace. Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable) nsManager.AddNamespace("d", worksheetSchema) Dim searchString As String = String.Format("//d:sheet[@name='{0}']", sheetName) Dim sheetNode As XmlNode = doc.SelectSingleNode(searchString, nsManager) If (Not (sheetNode) Is Nothing) Then ' Get the relId attribute. Dim relationAttribute As XmlAttribute = sheetNode.Attributes("r:id") If (Not (relationAttribute) Is Nothing) Then Dim relId As String = relationAttribute.Value Dim sheetPart As WorksheetPart = CType(xlDoc.WorkbookPart.GetPartById(relId), WorksheetPart) ' First, get the relationship between the document and the sheet. ' Load the contents of the workbook. Dim sheetDoc As XmlDocument = New XmlDocument sheetDoc.Load(sheetPart.GetStream(FileMode.Open)) If detectRows Then ' Retrieve the list of hidden rows. For Each node As System.Xml.XmlNode In sheetDoc.SelectNodes("//d:row[@hidden='1']", nsManager) ' For each hidden row, add information to the output list. Dim rowAttr As XmlAttribute = node.Attributes("r") If (Not (rowAttr) Is Nothing) Then itemList.Add(Convert.ToInt32(rowAttr.Value)) End If Next Else ' Retrieve the list of hidden columns For Each node As System.Xml.XmlNode In sheetDoc.SelectNodes("//d:cols/d:col", nsManager) Dim hiddenAttr As XmlAttribute = node.Attributes("hidden") If (Not (hiddenAttr) Is Nothing) Then If (hiddenAttr.Value = "1") Then ' Get the range of columns that are hidden. Dim minAttr As XmlAttribute = node.Attributes("min") Dim maxAttr As XmlAttribute = node.Attributes("max") If ((Not (minAttr) Is Nothing) AndAlso (Not (maxAttr) Is Nothing)) Then ' Finally, add the range of values to the list. Dim minValue As Integer = Convert.ToInt32(minAttr.Value) Dim maxValue As Integer = Convert.ToInt32(maxAttr.Value) Dim i As Integer = minValue Do While (i <= maxValue) itemList.Add(i) i = (i + 1) Loop End If End If End If Next End If End If End If Return itemList End FunctionC#FakePre-ab0fabd9cd3e41108d2fee3cad35c729-8a18cbe20cc5442aae23a6873a89e678
В эту процедуру передаются три параметра: полный путь к книге Excel 2007, имя листа и логическое значение, указывающее, искать ли скрытые строки. Если detectRows равен истине, процедура возвращает список скрытых строк. Если detectRows равен лжи, возвращается список скрытых столбцов. Затем с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML. Потом содержимое книги загружается в документ XML DOM. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию с квалификатором d. Найти узел, представляющий указанный лист в документе можно, используя атрибут «имя» узла //d:sheet.
Если узел найден, то отношение между книгой и листом получено. Сначала загружается содержимое листа. Если detectRows равен истина, то список скрытых строк получается использованием атрибута «скрытый» узла //d:row.
Примечание. |
---|
Строки нумеруются, начиная с 1. Столбцы нумеруются, начиная с нуля (0). |
Если detectRows равен ложь , то производится поиск скрытых столбцов с использованием атрибута «скрытый» узла //d:cols/d:col.
И наконец, список элементов возвращается вызывающей процедуре.
Экспорт диаграмм из книг
Для заданной книги Excel 2007 и названия диаграммы создать файл Word 2007 и экспортировать диаграмму.
Visual Basic
Public Sub XLExportChart(ByVal inputFileName As String, ByVal outputFileName As String, ByVal chartTitle As String) Const drawingMLSchema As String = "https://schemas.openxmlformats.org/drawingml/2006/main" Const chartMLSchema As String = "https://schemas.openxmlformats.org/drawingml/2006/chart" Dim chartFound As Boolean = False Dim xlDoc As SpreadsheetDocument = SpreadsheetDocument.Open(inputFileName, False) For Each sheetPart As WorksheetPart In xlDoc.WorkbookPart.WorksheetParts If (sheetPart.DrawingsPart Is Nothing) Then Continue For End If ' Loop through all the parts related to the worksheet. For Each chartPart As ChartPart In sheetPart.DrawingsPart.ChartParts ' A chart is found. Does it have the correct title? ' Create a namespace manager, so you can search. Dim nt As NameTable = New NameTable Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt) nsManager.AddNamespace("c", chartMLSchema) nsManager.AddNamespace("a", drawingMLSchema) ' Load the chart document from the part's stream, and ' search for the requested title. Dim chartDoc As XmlDocument = New XmlDocument(nt) chartDoc.Load(chartPart.GetStream) Dim titleNode As XmlNode = chartDoc.SelectSingleNode("//c:chart//c:title//a:t", nsManager) If (Not (titleNode) Is Nothing) Then If (String.Compare(titleNode.InnerText, chartTitle, True) = 0) Then Dim newDoc As WordprocessingDocument = WordprocessingDocument.Create(outputFileName, WordprocessingDocumentType.Document) newDoc.AddMainDocumentPart() newDoc.MainDocumentPart.AddPart(Of ChartPart)(chartPart) ' Tell the outer loops that you are finished. chartFound = True End If End If Next ' Because you need to export only a single chart, exit. If chartFound Then Exit Sub End If Next End SubC#FakePre-6f3a7bb75ce54755802941a4a0f09431-a2095d899052415885ad9896463bd4d2
В эту процедуру передаются три параметра: полный путь к книге, полный путь к выходному файлу и имя диаграммы.
Примечание. |
---|
В этой процедуре документ Word 2007 используется как временное хранилище для диаграммы, поэтому отношения не определяются. В результате документ нельзя открыть в Word. Код этой процедуры можно заменить кодом, который правильно добавляет часть к пакету документа. Образцы кода такого типа находятся здесь: 2007 Office System: пакет SDK Microsoft SDK для форматов Open XML. |
Сначала с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию chartML с квалификатором с и
После этого процедура в цикле ищет диаграмму с заданным названием по всем частям chartPart, используя выражение XPath //c:chart//c:title//a:t. Если такое выражение находится, то создается документ Word 2007 и в его пакет экспортируется часть chartPart.
Получить списки скрытых листов
Следующий код содержит создание списка всех скрытых листов в заданной книге.
Visual Basic
Public Function XLGetHiddenSheets(ByVal fileName As String) As List(Of String) Dim sheets As List(Of String) = New List(Of String)() Dim xlDoc As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, False) ' Get the main document part (workbook.xml). Dim doc As XmlDocument = New XmlDocument doc.Load(xlDoc.WorkbookPart.GetStream) ' Create a NamespaceManager to handle the default namespace, ' and create a prefix for the default namespace. Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable) nsManager.AddNamespace("default", doc.DocumentElement.NamespaceURI) For Each node As System.Xml.XmlNode In doc.SelectNodes("//default:sheets//default:sheet[@state='hidden']", nsManager) Dim sheetName As String = node.Attributes("name").Value sheets.Add(sheetName) Next Return sheets End FunctionC#FakePre-6f6d194990a9430282c30aef4549e51a-61b7e1817d274bbdaff23ac74c345094
В эту процедуру передается один параметр: полный путь к книге. Затем с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML и данные загружаются в XML-документ. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию SpreadsheetML для поиска скрытых листов.
Поиск скрытых листов в документе выполняется с использованием атрибута узла //default:sheets//default:sheet. Имя каждого найденного скрытого листа добавляется в список листов. После того как все листы просмотрены, список листов возвращается вызвавшей процедуре.
Получение значения ячейки в листах
Следующий код возвращает значение ячейки в листе.
Visual Basic
Public Function XLGetCellValue(ByVal fileName As String, ByVal sheetName As String, ByVal addressName As String) As String Const worksheetSchema As String = "https://schemas.openxmlformats.org/spreadsheetml/2006/main" Const sharedStringSchema As String = "https://schemas.openxmlformats.org/spreadsheetml/2006/main" Dim cellValue As String = Nothing ' Retrieve the stream containing the requested ' worksheet's information. Dim xlDoc As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, False) ' Get the main document part (workbook.xml). Dim doc As XmlDocument = New XmlDocument doc.Load(xlDoc.WorkbookPart.GetStream) ' Create a namespace manager, so you can search. ' Add a prefix (d) for the default namespace. Dim nt As NameTable = New NameTable Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt) nsManager.AddNamespace("d", worksheetSchema) nsManager.AddNamespace("s", sharedStringSchema) Dim searchString As String = String.Format("//d:sheet[@name='{0}']", sheetName) Dim sheetNode As XmlNode = doc.SelectSingleNode(searchString, nsManager) If (Not (sheetNode) Is Nothing) Then ' Get the relId attribute. Dim relationAttribute As XmlAttribute = sheetNode.Attributes("r:id") If (Not (relationAttribute) Is Nothing) Then Dim relId As String = relationAttribute.Value ' Load the contents of the workbook. Dim sheetDoc As XmlDocument = New XmlDocument(nt) sheetDoc.Load(xlDoc.WorkbookPart.GetPartById(relId).GetStream) Dim cellNode As XmlNode = sheetDoc.SelectSingleNode(String.Format("//d:sheetData/d:row/d:c[@r='{0}']", addressName), nsManager) If (Not (cellNode) Is Nothing) Then Dim typeAttr As XmlAttribute = cellNode.Attributes("t") Dim cellType As String = String.Empty If (Not (typeAttr) Is Nothing) Then cellType = typeAttr.Value End If Dim valueNode As XmlNode = cellNode.SelectSingleNode("d:v", nsManager) If (Not (valueNode) Is Nothing) Then cellValue = valueNode.InnerText End If If (cellType = "b") Then If (cellValue = "1") Then cellValue = "TRUE" Else cellValue = "FALSE" End If ElseIf (cellType = "s") Then If (Not (xlDoc.WorkbookPart.SharedStringTablePart) Is Nothing) Then Dim stringDoc As XmlDocument = New XmlDocument(nt) stringDoc.Load(xlDoc.WorkbookPart.SharedStringTablePart.GetStream) ' Add the string schema to the namespace manager. nsManager.AddNamespace("s", sharedStringSchema) Dim requestedString As Integer = Convert.ToInt32(cellValue) Dim strSearch As String = String.Format("//s:sst/s:si[{0}]", (requestedString + 1)) Dim stringNode As XmlNode = stringDoc.SelectSingleNode(strSearch, nsManager) If (Not (stringNode) Is Nothing) Then cellValue = stringNode.InnerText End If End If End If End If End If End If Return cellValue End FunctionC#FakePre-5b912e2300404baca7ac5055322b6869-1bd8b9082cc745e59dc03537ee55e81a
В эту процедуру передаются три параметра: полный путь к книге, имя листа и адрес ячейки, величину которой нужно получить. Затем с помощью метода Open объекта SpreadsheetDocument входной файл открывается как пакет Open XML и данные загружаются в XML-документ. Затем устанавливается диспетчер пространства имен, используя объект XmlNamespaceManager и ссылку на пространство имен по умолчанию worksheetSchema с квалификатором d и на пространство имен sharedStringSchema с квалификатором s. Пространство имен sharedStringSchema ссылается на часть SharedStringTablePart part, содержащую строки, разделяемые между клетками.
Потом по атрибуту «имя» узла //d:sheet извлекается узел, представляющий указанный лист в главной книге. Если узел найден, то из листа извлекается значение кода связи, которое используется для загрузки листа в документ XML. Затем извлекается значение. Если в узле атрибут t содержит s, значит, это разделяемая строка, и ее значение нужно искать в части SharedStringTablePart. Иначе значение получается непосредственно из узла.
Примечание. |
---|
Этот код проверяет индивидуально только логические и строковые величины. |
Наконец, процедура возвращает или значение ячейки, или логическое значение, указывающее на результат поиска**.**
Заключение
Как показано в этой статье, работа с файлами Excel 2007 и PowerPoint 2007 намного легче предварительной версией пакета SDK Microsoft для форматов Open XML. Во второй части этой серии статей (которая скоро выйдет) я опишу другие общие действия, которые можно производить с файлами Excel 2007 и PowerPoint 2007.
Дополнительные источники
Для получения дополнительных сведений можно использовать следующие материалы.
В сети: Предварительная версия пакета SDK Microsoft для форматов Open XML
Загрузка: Система Office 2007 пакет SDK Microsoft SDK для форматов Open XML.
-
Примечание. Это адрес файла в формате PDF достаточного размера.
Скоро выйдет
- Использование объектной модели Open XML для операций над файлами Excel 2007 и PowerPoint 2007 (часть 2 из 2)