개요 : 「Microsoft
SDK for Open XML Formats 기술 프리뷰」는 Open XML 형식의 파일에 액세스하기 위한 라이브러리입니다. 이 문서에서는 Microsoft Office Excel 2007 파일과 Microsoft Office PowerPoint 2007 파일의 액세스와 조작에 사용할 수 있는 Open XML 개체 모델 코드를 설명합니다.
Frank Rice, Microsoft Corporation
2007 년 9 월
적용 대상 : Microsoft Office Excel 2007, Microsoft Office PowerPoint 2007
목차
개요
2007 Microsoft Office system에서는 Office Open XML 형식으로 불리는 XML 기반의 새로운 파일 형식이 도입됩니다. Microsoft Office Word 2007, Microsoft Office
Excel 2007 및 Microsoft Office PowerPoint 2007에서는 이 파일 형식이 기본값의 파일
형식으로서 사용됩니다. Microsoft에서는 Microsoft .NET Framework 3.0 기술의 일부로서 System.IO.Packaging
네임 스페이스로 이러한 파일에 액세스하기 위한 라이브러리가 「Microsoft
SDK for Open XML Formats 기술 프리뷰」에 있습니다. Open XML 개체 모델은 System.IO.Packaging
API 를 기반으로 생성되어, Open XML 문서를 조작하기 위한 엄밀하게 형식 지정된 파트 클래스를 갖추고 있습니다.
이 문서에서는 Excel 2007에서 PowerPoint 2007 의 Open XML 패키지에 액세스하여 사용할 수 있는
코드 예를 보여줍니다.
다음 코드에서는 워크시트에서 주석을 검색하여 XML 문서에 추가합니다.
Public Function XLGetCommentsAsXML(ByVal fileName As String) As XmlDocument
Const workbookSchema As String = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
Const relationSchema As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
Dim resultDoc As XmlDocument = New XmlDocument
resultDoc.LoadXml("<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?%gt;<AllComments /%gt;")
Dim resultDocElement As XmlNode = resultDoc.DocumentElement
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)
' Manage namespaces to perform XML XPath queries.
Dim nt As NameTable = New NameTable
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
nsManager.AddNamespace("w", workbookSchema)
nsManager.AddNamespace("r", relationSchema)
Dim search As String = String.Format("//w:sheets/w:sheet")
Dim nodes As XmlNodeList = doc.SelectNodes(search, nsManager)
For Each sheetNode As XmlNode In nodes
Dim attr As XmlAttribute = sheetNode.Attributes("name")
Dim sheetName As String = attr.Value
attr = sheetNode.Attributes("r:id")
Dim sheetID As String = attr.Value
Dim sheetPart As WorksheetPart = CType(xlDoc.WorkbookPart.GetPartById(sheetID), WorksheetPart)
If ((Not (sheetPart) Is Nothing) AndAlso (Not (sheetPart.WorksheetCommentsPart) Is Nothing)) Then
Dim commentDoc As XmlDocument = New XmlDocument
commentDoc.Load(sheetPart.WorksheetCommentsPart.GetStream)
Dim newSheetNode As XmlNode = resultDoc.CreateNode(XmlNodeType.Element, "sheet", "")
Dim nameAttr As XmlAttribute = newSheetNode.Attributes.Append(resultDoc.CreateAttribute("name"))
nameAttr.Value = sheetName
newSheetNode.InnerXml = commentDoc.DocumentElement.OuterXml
resultDocElement.AppendChild(newSheetNode)
End If
Next
Return resultDoc
End Function
public static XmlDocument XLGetCommentsAsXML(string fileName)
{
const string workbookSchema = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
const string relationSchema = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
XmlDocument resultDoc = new XmlDocument();
resultDoc.LoadXml(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?><AllComments />");
XmlNode resultDocElement = resultDoc.DocumentElement;
using (SpreadsheetDocument xlDoc = SpreadsheetDocument.Open(fileName, false))
{
// Get the main document part (workbook.xml).
XmlDocument doc = new XmlDocument();
doc.Load(xlDoc.WorkbookPart.GetStream());
// Manage namespaces to perform XML XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", workbookSchema);
nsManager.AddNamespace("r", relationSchema);
string search = string.Format("//w:sheets/w:sheet");
XmlNodeList nodes = doc.SelectNodes(search, nsManager);
foreach (XmlNode sheetNode in nodes)
{
XmlAttribute attr = sheetNode.Attributes["name"];
string sheetName = attr.Value;
attr = sheetNode.Attributes["r:id"];
string sheetID = attr.Value;
WorksheetPart sheetPart = xlDoc.WorkbookPart.GetPartById(sheetID) as WorksheetPart;
if (sheetPart != null && sheetPart.WorksheetCommentsPart != null)
{
XmlDocument commentDoc = new XmlDocument();
commentDoc.Load(sheetPart.WorksheetCommentsPart.GetStream());
XmlNode newSheetNode = resultDoc.CreateNode(XmlNodeType.Element, "sheet", "");
XmlAttribute nameAttr = newSheetNode.Attributes.Append(resultDoc.CreateAttribute("name"));
nameAttr.Value = sheetName;
newSheetNode.InnerXml = commentDoc.DocumentElement.OuterXml;
resultDocElement.AppendChild(newSheetNode);
}
}
}
return resultDoc;
}
이 프로시저에서는 1 개의 매개 변수 (통합 문서의 전체 경로)를 전달합니다. 발견된 주석을 포함한 XML 문서의 셸을
생성합니다. 출력은 다음 코드 예와 같습니다.
<AllComments>
<sheet name="Sheet1">
<comments>
<!-- The contents from the sheet's related comments part -->
</comments>
</sheet>
...
</AllComments>
다음은 SpreadsheetDocument 개체의 Open 메서드를 사용하여 입력파일을
Open XML 패키지로서 열고, 데이터를 XML 문서에 로드합니다. 또한 XmlNamespaceManager
개체를 사용하여 네임 스페이스 관리자를 설정합니다. w 수식자를 사용하여 기본값의 workBookSchema
네임 스페이스 참조를 r 수식자를 사용하여 relationSchema 네임 스페이스 참조를
설정합니다. XPath 식//w:sheets/w:sheet를 설치하여 패키지내의 각 워크시트를
반복 처리합니다.
다음은 패키지내의 각 워크시트의 이름과 관계 ID 를 검색합니다. 그 ID 를 포함한 worksheetPart
파트와 worksheetCommentsPart 파트가 존재하는 경우, worksheetCommentsPart 을 XML
문서에 로드합니다. 마지막으로 worksheetPart 파트의 주석을 출력 문서에 삽입하여 생성된 XML 문서를 호출자
프로시저에 반환합니다.
워크시트 이름 검색
다음 코드에서는 모든 워크시트의 이름 목록을 검색합니다.
Public Function XLGetSheetInfo(ByVal fileName As String) As List(Of String)
Dim sheets As List(Of String) = New List(Of String)
Dim xlPackage As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, False)
Dim workbook As WorkbookPart = xlPackage.WorkbookPart
Dim workbookstr As Stream = workbook.GetStream
Dim doc As XmlDocument = New XmlDocument
doc.Load(workbookstr)
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable)
nsManager.AddNamespace("default", doc.DocumentElement.NamespaceURI)
Dim nodelist As XmlNodeList = doc.SelectNodes("//default:sheets/default:sheet", nsManager)
For Each node As XmlNode In nodelist
Dim sheetName As String = String.Empty
sheetName = node.Attributes("name").Value
sheets.Add(sheetName)
Next
Return sheets
End Function
public static List<string> XLGetSheetInfo(string fileName)
{
List<string> sheets = new List<string>();
using (SpreadsheetDocument xlPackage = SpreadsheetDocument.Open(fileName, false))
{
WorkbookPart workbook = xlPackage.WorkbookPart;
Stream workbookstr = workbook.GetStream();
XmlDocument doc = new XmlDocument();
doc.Load(workbookstr);
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("default", doc.DocumentElement.NamespaceURI);
XmlNodeList nodelist = doc.SelectNodes("//default:sheets/default:sheet", nsManager);
foreach (XmlNode node in nodelist)
{
string sheetName = string.Empty;
sheetName = node.Attributes["name"].Value;
sheets.Add(sheetName);
}
}
return sheets;
}
우선, SpreadsheetDocument 개체의 Open 메서드를 사용하여, 입력파일을
Open XML 패키지로서 열어, 데이터를 XML 문서에 로드합니다. 또한 XmlNamespaceManager
개체를 사용하여 네임 스페이스 관리자를 설정합니다. w 수식자를 사용하여 기본값 workBookSchema
네임 스페이스 참조를 r 수식자를 사용하여 relationSchema 네임 스페이스 참조를
설정합니다. 또한 검색 XPath 식//default:sheets/default:sheet 를 설정하여
통합 문서의 각 노드를 반복 처리하고, 패키지내의 각 워크시트의 이름을 검색합니다.
마지막으로 워크시트 이름의 목록을 호출자 프로시저에 반환합니다.
워크시트에서 셀 쓰기
다음 코드에서는 워크시트의 셀에 값을 씁니다.
Public Sub XLWrite2Cell(ByVal fileName As String, ByVal sheetName As String, ByVal addressName As String)
Const worksheetNamespace As String = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
Dim xlPackage As SpreadsheetDocument = SpreadsheetDocument.Open(fileName, True)
' Get the main document part (workbook.xml).
Dim workbookPart As WorkbookPart = xlPackage.WorkbookPart
' Load the contents of the workbook.
Dim doc As XmlDocument = New XmlDocument
doc.Load(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("d", doc.DocumentElement.NamespaceURI)
nsManager.AddNamespace("w", worksheetNamespace)
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 relationship id attribute.
Dim relationAttribute As XmlAttribute = sheetNode.Attributes("r:id")
If (Not (relationAttribute) Is Nothing) Then
Dim relId As String = relationAttribute.Value
Dim worksheetPart As WorksheetPart = CType(workbookPart.GetPartById(relId), WorksheetPart)
Dim sheetDoc As XmlDocument = New XmlDocument
sheetDoc.Load(worksheetPart.GetStream)
Dim cellNode As XmlNode = sheetDoc.SelectSingleNode(String.Format("//w:sheetData/w:row/w:c[@r='{0}']", addressName), nsManager)
If (cellNode Is Nothing) Then
cellNode = sheetDoc.CreateElement("c", worksheetNamespace)
cellNode.Attributes.Append(sheetDoc.CreateAttribute("r"))
cellNode.Attributes("r").Value = addressName
Dim r As System.Text.RegularExpressions.Regex = New System.Text.RegularExpressions.Regex("(?<col>\D+)(?<row>\d+)")
Dim rowNumber As String = r.Match(addressName).Result("${row}")
cellNode.Attributes.Append(sheetDoc.CreateAttribute("s"))
cellNode.Attributes("s").Value = "0"
Dim rowNode As XmlNode = sheetDoc.SelectSingleNode(String.Format("//w:sheetData/w:row[@r='{0}']", rowNumber), nsManager)
If (rowNode Is Nothing) Then
Dim sheetDataNode As XmlNode = sheetDoc.SelectSingleNode("//w:sheetData", nsManager)
If (Not (sheetDataNode) Is Nothing) Then
rowNode = sheetDoc.CreateElement("row", worksheetNamespace)
rowNode.Attributes.Append(sheetDoc.CreateAttribute("r"))
rowNode.Attributes("r").Value = rowNumber
rowNode.AppendChild(cellNode)
sheetDataNode.AppendChild(rowNode)
End If
Else
Dim styleAttr As XmlAttribute = rowNode.Attributes("s")
If (Not (styleAttr) Is Nothing) Then
cellNode.Attributes("s").Value = styleAttr.Value
End If
Dim biggerNode As XmlNode = Nothing
For Each node As System.Xml.XmlNode In rowNode.ChildNodes
If (Double.Parse(node.Attributes("r").Value) > Double.Parse(addressName)) Then
biggerNode = node
End If
Next
If (biggerNode Is Nothing) Then
rowNode.AppendChild(cellNode)
Else
rowNode.InsertBefore(cellNode, biggerNode)
End If
End If
End If
' =============
' Insert code to work with cellNode here.
' =============
' For example:
Dim valueNode As XmlNode = cellNode.SelectSingleNode(".//w:v", nsManager)
If (valueNode Is Nothing) Then
valueNode = sheetDoc.CreateElement("v", worksheetNamespace)
cellNode.AppendChild(valueNode)
End If
valueNode.InnerText = "12345"
' Note that this will not display string values--those must
' be retrieved from the shared strings part.
' See the code example that demonstrates retrieving
' a value from an Excel cell for the complete code.
MessageBox.Show(("Value = " + valueNode.InnerText))
' Save the worksheet part.
Dim st As Stream = worksheetPart.GetStream(FileMode.Create)
sheetDoc.Save(st)
'xlPackage.Save();
'doc.Save(workbookPart.GetStream(FileMode.Create));
' ============
' End example code.
' ============
End If
End If
End Sub
public static void XLWrite2Cell(string fileName, string sheetName, string addressName)
{
const string worksheetNamespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
using (SpreadsheetDocument xlPackage = SpreadsheetDocument.Open(fileName, true))
{
// Get the main document part (workbook.xml).
WorkbookPart workbookPart = xlPackage.WorkbookPart;
// Load the contents of the workbook.
XmlDocument doc = new XmlDocument();
doc.Load(workbookPart.GetStream());
// Create a NamespaceManager to handle the default namespace,
// and create a prefix for the default namespace.
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("d", doc.DocumentElement.NamespaceURI);
nsManager.AddNamespace("w", worksheetNamespace);
string searchString = string.Format("//d:sheet[@name='{0}']", sheetName);
XmlNode sheetNode = doc.SelectSingleNode(searchString, nsManager);
if (sheetNode != null)
{
// Get the relationship id attribute.
XmlAttribute relationAttribute = sheetNode.Attributes["r:id"];
if (relationAttribute != null)
{
string relId = relationAttribute.Value;
WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(relId);
XmlDocument sheetDoc = new XmlDocument();
sheetDoc.Load(worksheetPart.GetStream());
XmlNode cellNode = sheetDoc.SelectSingleNode(string.Format("//w:sheetData/w:row/w:c[@r='{0}']", addressName), nsManager);
if (cellNode == null)
{
cellNode = sheetDoc.CreateElement("c", worksheetNamespace);
cellNode.Attributes.Append(sheetDoc.CreateAttribute("r"));
cellNode.Attributes["r"].Value = addressName;
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"(?<col>\D+)(?<row>\d+)");
string rowNumber = r.Match(addressName).Result("${row}");
cellNode.Attributes.Append(sheetDoc.CreateAttribute("s"));
cellNode.Attributes["s"].Value = "0";
XmlNode rowNode = sheetDoc.SelectSingleNode(string.Format("//w:sheetData/w:row[@r='{0}']", rowNumber), nsManager);
if (rowNode == null)
{
XmlNode sheetDataNode = sheetDoc.SelectSingleNode("//w:sheetData", nsManager);
if (sheetDataNode != null)
{
rowNode = sheetDoc.CreateElement("row", worksheetNamespace);
rowNode.Attributes.Append(sheetDoc.CreateAttribute("r"));
rowNode.Attributes["r"].Value = rowNumber;
rowNode.AppendChild(cellNode);
sheetDataNode.AppendChild(rowNode);
}
}
else
{
XmlAttribute styleAttr = rowNode.Attributes["s"];
if (styleAttr != null)
{
cellNode.Attributes["s"].Value = styleAttr.Value;
}
XmlNode biggerNode = null;
foreach (System.Xml.XmlNode node in rowNode.ChildNodes)
{
if (double.Parse(node.Attributes["r"].Value) > double.Parse(addressName))
{
biggerNode = node;
break; /* TRANSWARNING: check that break is in correct scope */
}
}
if (biggerNode == null)
{
rowNode.AppendChild(cellNode);
}
else
{
rowNode.InsertBefore(cellNode, biggerNode);
}
}
}
// =============
// Insert code to work with cellNode here.
// =============
// For example:
XmlNode valueNode = cellNode.SelectSingleNode(".//w:v", nsManager);
if (valueNode == null)
{
valueNode = sheetDoc.CreateElement("v", worksheetNamespace);
cellNode.AppendChild(valueNode);
}
valueNode.InnerText = "12345";
// Note that this won't display string values--those must
// be retrieved from the shared strings part.
// See the code example that demonstrates retrieving
// a value from an Excel cell for the complete code.
MessageBox.Show("Value = " + valueNode.InnerText);
// Save the worksheet part.
Stream st = worksheetPart.GetStream(FileMode.Create);
sheetDoc.Save(st);
//xlPackage.Save();
//doc.Save(workbookPart.GetStream(FileMode.Create));
// ============
// End example code.
// ============
}
}
}
}
이 프로시저에서는 통합 문서에의 전체 경로, 워크시트의 이름 및 기입처의 셀 주소의 3 개 매개 변수를 전달합니다.
그리고, SpreadsheetDocument 개체의 Open 메서드를 사용하여 입력파일을
Open XML 패키지로서 열어, 데이터를 XML 문서에 로드합니다. 또한 XmlNamespaceManager
개체를 사용하여 네임 스페이스 관리자를 설정합니다. d 수식자를 사용하여 기본값 NamespaceURI
네임 스페이스 참조를 w 수식자를 사용하여 worksheetNamespace 네임
스페이스 참조를 설정합니다.
//d:sheet 노드의 name
특성을 선택하고, 주 통합 문서
파트내의 지정 워크시트를 나타내는 노드를 검색합니다. 노드가 발견되면, 그 워크시트의 관계 ID 를 검색하여 ID 를 사용하여 워크시트를 XML 문서에 로드합니다.
그리고 몇가지 구문에서 기입처의 셀을 찾습니다. 셀이 발견되지 않는 경우,
행을 검색합니다. 셀이 발견되지 않으면, 생성해야 합니다. 행이 발견되지 않은 경우도, 노드를 생성하고,
올바른 위치에 셀을 생성해야 합니다.
행과 셀이 생성된 다음에 셀을 조작하는 코드가 필요합니다. 이 프로시저에는 문자열 값을 셀에 쓰는 샘플코드가
포함돼 있습니다.
프레젠테이션 슬라이드 제목 검색
다음 코드에서는 PowerPoint 2007 프레젠테이션 슬라이드 제목 목록을 검색합니다.
Public Function PPTGetSlideTitles(ByVal fileName As String) As List(Of String)
Const presentationmlNamespace As String = "http://schemas.openxmlformats.org/presentationml/2006/main"
Dim titles As List(Of String) = New System.Collections.Generic.List(Of String)
Dim pptDoc As PresentationDocument = PresentationDocument.Open(fileName, False)
' Manage namespaces to perform XML XPath queries.
Dim nt As NameTable = New NameTable
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
nsManager.AddNamespace("p", presentationmlNamespace)
For Each slidePart As SlidePart In pptDoc.PresentationPart.SlideParts
Dim slideDoc As XmlDocument = New XmlDocument(nt)
slideDoc.Load(slidePart.GetStream)
Dim titleNode As XmlNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager)
If (Not (titleNode) Is Nothing) Then
titles.Add(titleNode.ParentNode.ParentNode.ParentNode.InnerText)
End If
Next
Return titles
End Function
public static List>string> PPTGetSlideTitles(string fileName)
{
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
List>string> titles = new System.Collections.Generic.List>string>();
using (PresentationDocument pptDoc = PresentationDocument.Open(fileName, false))
{
// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("p", presentationmlNamespace);
foreach (SlidePart slidePart in pptDoc.PresentationPart.SlideParts)
{
XmlDocument slideDoc = new XmlDocument(nt);
slideDoc.Load(slidePart.GetStream());
XmlNode titleNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager);
if (titleNode != null)
{
titles.Add(titleNode.ParentNode.ParentNode.ParentNode.InnerText);
}
}
}
return titles;
}
이 프로시저에서는 PowerPoint 2007 프레젠테이션 문서에 전체 경로 하나의 매개 변수를 전달합니다.
다음은 PresentationDocument 개체의 Open 메서드를 사용하여 문서를
엽니다. 또한 XmlNamespaceManager 개체를 사용하여 네임 스페이스 관리자를 설정합니다. p
수식자를 사용하여 기본값의 presentationML 네임 스페이스 참조를 설정합니다. 슬라이드 파트를
반복처리하고, 각 파트를 XML 문서에 로드합니다. //p:sp//p:ph 노드의 title
특성 또는 ctrTitle 특성을 사용하여 각 슬라이드 제목 검색합니다. 마지막으로 슬라이드 제목 목록을
반환합니다.
프레젠테이션 슬라이드 삭제
다음 코드에서는 프레젠테이션의 슬라이드를 삭제합니다.
Public Function PPTDeleteSlide(ByVal fileName As String, ByVal title As String) As Boolean
Const presentationmlNamespace As String = "http://schemas.openxmlformats.org/presentationml/2006/main"
Const relationshipNamespace As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
Dim returnValue As Boolean = False
Dim pptDoc As PresentationDocument = PresentationDocument.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("p", presentationmlNamespace)
nsManager.AddNamespace("rel", relationshipNamespace)
Dim xDoc As XmlDocument = New XmlDocument(nt)
xDoc.Load(pptDoc.PresentationPart.GetStream)
Dim partToDelete As SlidePart = Nothing
Dim partId As String = Nothing
For Each slidePart As SlidePart In pptDoc.PresentationPart.SlideParts
Dim slideDoc As XmlDocument = New XmlDocument(nt)
slideDoc.Load(slidePart.GetStream)
Dim titleNode As XmlNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager)
If (Not (titleNode) Is Nothing) Then
Dim titleText As String = titleNode.ParentNode.ParentNode.ParentNode.InnerText
If (String.Compare(titleText, title, True) = 0) Then
partToDelete = slidePart
partId = pptDoc.PresentationPart.GetIdOfPart(slidePart)
End If
End If
Next
If (Not (partToDelete) Is Nothing) Then
pptDoc.PresentationPart.DeletePart(partToDelete)
Dim searchString As String = String.Format("//p:sldId[@rel:id='{0}']", partId)
Dim slideRelNode As XmlNode = xDoc.SelectSingleNode(searchString, nsManager)
If (Not (slideRelNode) Is Nothing) Then
slideRelNode.ParentNode.RemoveChild(slideRelNode)
End If
xDoc.Save(pptDoc.PresentationPart.GetStream(FileMode.Create))
returnValue = True
End If
Return returnValue
End Function
public static bool PPTDeleteSlide(string fileName, string title)
{
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
const string relationshipNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
bool returnValue = false;
using (PresentationDocument pptDoc = PresentationDocument.Open(fileName, true))
{
// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("p", presentationmlNamespace);
nsManager.AddNamespace("rel", relationshipNamespace);
XmlDocument xDoc = new XmlDocument(nt);
xDoc.Load(pptDoc.PresentationPart.GetStream());
SlidePart partToDelete = null;
string partId = null;
foreach (SlidePart slidePart in pptDoc.PresentationPart.SlideParts)
{
XmlDocument slideDoc = new XmlDocument(nt);
slideDoc.Load(slidePart.GetStream());
XmlNode titleNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager);
if (titleNode != null)
{
string titleText = titleNode.ParentNode.ParentNode.ParentNode.InnerText;
if (string.Compare(titleText, title, true) == 0)
{
partToDelete = slidePart;
partId = pptDoc.PresentationPart.GetIdOfPart(slidePart);
break;
}
}
}
if (partToDelete != null)
{
pptDoc.PresentationPart.DeletePart(partToDelete);
string searchString = string.Format("//p:sldId[@rel:id='{0}']", partId);
XmlNode slideRelNode = xDoc.SelectSingleNode(searchString, nsManager);
if (slideRelNode != null)
{
slideRelNode.ParentNode.RemoveChild(slideRelNode);
}
xDoc.Save(pptDoc.PresentationPart.GetStream(FileMode.Create));
returnValue = true;
}
}
return returnValue;
}
이 프로시저에서는 PowerPoint 2007 문서에의 전체 경로와 삭제하는 슬라이드 이름의 2 개의 매개
변수를 전달합니다. 다음은 PresentationDocument 개체의 Open 메서드를 사용하여
문서를 엽니다. 또한 XmlNamespaceManager 개체를 사용하여 네임 스페이스 관리자를
설정합니다. p
수식자를 사용하여 기본값의 presentationML 네임 스페이스 참조를 rel
수식자를 사용하여 relationshipNamespace
네임 스페이스 참조를 설정합니다. 슬라이드 파트를 반복처리하고, 각 파트를 XML 문서에 로드합니다. //p:sp//p:ph
노드의 title 특성 또는 ctrTitle 특성을 사용하여, 각 슬라이드 제목 검색합니다.
다음은 슬라이드 파트에서 검색한 제목과 프로시저에게 건네진 슬라이드 제목 인수를 비교합니다. 지정된 슬라이드가
발견되었을 경우는 그 슬라이드 파트를 삭제합니다. 또한 주 프레젠테이션 파트내의 관계 노드도 삭제합니다. 마지막으로
슬라이드가 정상적으로 삭제되었는지 보여주는 Boolean 값을 반환합니다.
프레젠테이션 슬라이드 횟수
다음 코드에서는 프레젠테이션 데크의 슬라이드 수를 반환합니다.
Public
Function PPTGetSlideCount(ByVal fileName As
String) As
Integer
Dim returnValue As
Integer = 0
Dim pptDoc As PresentationDocument = PresentationDocument.Open(fileName, False)
Using (pptDoc)
returnValue = pptDoc.PresentationPart.GetPartsCountOfType(Of SlidePart)()
End Using
Return returnValue
End
Function
public
static
int PPTGetSlideCount(string fileName)
{
int returnValue = 0;
using (PresentationDocument pptDoc = PresentationDocument.Open(fileName, false))
{
returnValue = pptDoc.PresentationPart.GetPartsCountOfType<SlidePart>();
}
return returnValue;
}
이 프로시저에서는 PowerPoint 2007 문서에의 전체 경로인 1 개의 매개 변수를 전달합니다. 다음은 PresentationDocument
개체의 Open 메서드를 사용하여 문서를 엽니다. 프레젠테이션에서 GetPartsCountOfType
속성 값을 검색합니다. 프로시저가 그 값을 반환합니다.
슬라이드 제목 변경
다음 코드에서는 슬라이드 제목을 변경합니다.
Public Function PPTModifySlideTitle(ByVal fileName As String, ByVal oldSlideTitle As String, ByVal newSlideTitle As String) As Boolean
Const presentationmlNamespace As String = "http://schemas.openxmlformats.org/presentationml/2006/main"
Const drawingmlNamespace As String = "http://schemas.openxmlformats.org/drawingml/2006/main"
Dim returnValue As Boolean = False
Dim pptPackage As PresentationDocument = PresentationDocument.Open(fileName, True)
Dim presentationPart As PresentationPart = pptPackage.PresentationPart
Dim slideParts As IEnumerable = presentationPart.SlideParts
' Manage namespaces to perform Xml XPath queries.
Dim nt As NameTable = New NameTable
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
nsManager.AddNamespace("p", presentationmlNamespace)
nsManager.AddNamespace("a", drawingmlNamespace)
For Each slidePart As SlidePart In slideParts
Dim doc As XmlDocument = New XmlDocument(nt)
doc.Load(slidePart.GetStream)
Dim xNode As XmlNode = doc.SelectSingleNode("//a:t", nsManager)
If (Not (xNode) Is Nothing) Then
If (String.Compare(xNode.InnerText, oldSlideTitle, True) = 0) Then
xNode.InnerText = newSlideTitle
doc.Save(slidePart.GetStream)
'pptPackage.Save();
returnValue = True
End If
End If
Next
Return returnValue
End Function
public static bool PPTModifySlideTitle(string fileName, string oldSlideTitle, string newSlideTitle)
{
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
const string drawingmlNamespace = "http://schemas.openxmlformats.org/drawingml/2006/main";
bool returnValue = false;
using (PresentationDocument pptPackage = PresentationDocument.Open(fileName, true))
{
PresentationPart presentationPart = pptPackage.PresentationPart;
IEnumerable<SlidePart> slideParts = presentationPart.SlideParts;
// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("p", presentationmlNamespace);
nsManager.AddNamespace("a", drawingmlNamespace);
foreach (SlidePart slidePart in slideParts)
{
XmlDocument doc = new XmlDocument(nt);
doc.Load(slidePart.GetStream());
XmlNode xNode = doc.SelectSingleNode("//a:t", nsManager);
if (xNode != null)
{
if (string.Compare(xNode.InnerText, oldSlideTitle, true) == 0)
{
xNode.InnerText = newSlideTitle;
doc.Save(slidePart.GetStream());
//pptPackage.Save();
returnValue = true;
break;
}
}
}
}
return returnValue;
}
이 프로시저에서는 PowerPoint 2007 문서에의 전체 경로, 대상 슬라이드 제목, 슬라이드가 새로운 제목의
세가지 매개 변수를 전달합니다. 다음은 PresentationDocument 개체의 Open
메서드를 사용하여 문서를 엽니다. 또한 각 슬라이드를 반복 처리하고, 프로시저에 건네준 제목을 가지는 슬라이드를
찾습니다. 그러기 위해서는 XmlNamespaceManager 개체를 사용하여 네임 스페이스
관리자를 설정합니다. p 수식자를 사용하여 기본값의 presentationml 네임
스페이스 참조를 a
수식자를 사용하여 drawingmlNamespace 네임 스페이스 참조를 설정합니다. 슬라이드 파트를
반복처리하고, 각 파트를 XML 문서에 로드합니다. 다음은//a:t 노드에서 각 슬라이드 파트를 선택합니다.
메모
: |
|
이 코드에서는 최초로 검색 되는 텍스트가 제목인 것을 전제로 합니다. 또한 제목에 여러개의
폰트나 일반 텍스트 이외의 데이터가 포함된 경우, PowerPoint 2007에서는 제목이 여러 요소에 분할됩니다. 그러한 경우, 이 코드에서는 일치하는 제목이 검색되지 않습니다.
|
다음은 슬라이드 파트에서 검색한 제목과 프로시저에게 건네진 슬라이드 제목을 비교합니다. 지정된 슬라이드가 발견되었을
경우는 그 슬라이드 파트에 새로운 제목을 씁니다. 마지막으로 슬라이드가 정상적으로 삭제되었는지 보여주는 Boolean
값을 반환합니다.
프레젠테이션 슬라이드 순서 변경
다음 코드에서는 슬라이드의 프레젠테이션 데크의 슬라이드 표시 순서를 변경합니다.
Public Function PPTReorderSlides(ByVal fileName As String, ByVal originalPosition As Integer, ByVal newPosition As Integer) As Integer
Const presentationmlNamespace As String = "http://schemas.openxmlformats.org/presentationml/2006/main"
Dim returnValue As Integer = -1
Dim pptPackage As PresentationDocument = PresentationDocument.Open(fileName, True)
Dim presentationPart As PresentationPart = pptPackage.PresentationPart
If (Not (presentationPart) Is Nothing) Then
Dim doc As XmlDocument = New XmlDocument
doc.Load(presentationPart.GetStream)
' Manage namespaces to perform XPath queries.
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable)
nsManager.AddNamespace("p", presentationmlNamespace)
Dim nodes As XmlNodeList = doc.SelectNodes("//p:sldId", nsManager)
If (Not (nodes) Is Nothing) Then
Dim slideCount As Integer = nodes.Count
Dim maxPosition As Integer = slideCount
If (slideCount > 0) Then
If (originalPosition = -1) Then
originalPosition = maxPosition
End If
If (newPosition = -1) Then
newPosition = maxPosition
End If
If (originalPosition > maxPosition) Then
originalPosition = maxPosition
End If
If (newPosition > maxPosition) Then
newPosition = maxPosition
End If
If ((originalPosition < 0) OrElse (newPosition < 0)) Then
' Something is wrong. Raise an exception.
Throw New ArgumentException("Invalid parameter. Both original and new positions must be integers between -1 and the total number of slides.")
End If
If (originalPosition <> newPosition) Then
Dim parentNode As XmlNode = doc.SelectSingleNode("//p:sldIdLst", nsManager)
If (Not (parentNode) Is Nothing) Then
' Get references to both slide nodes.
Dim originalNode As XmlNode = Nothing
Dim newNode As XmlNode = Nothing
Dim nodeSearch As String = Nothing
Dim attr As XmlAttribute = nodes((originalPosition - 1)).Attributes("id")
If (Not (attr) Is Nothing) Then
nodeSearch = String.Format("./p:sldId[@id='{0}']", attr.Value)
originalNode = parentNode.SelectSingleNode(nodeSearch, nsManager)
End If
attr = nodes((newPosition - 1)).Attributes("id")
If (Not (attr) Is Nothing) Then
nodeSearch = String.Format("./p:sldId[@id='{0}']", attr.Value)
newNode = parentNode.SelectSingleNode(nodeSearch, nsManager)
End If
If ((Not (originalNode) Is Nothing) AndAlso (Not (newNode) Is Nothing)) Then
If (newPosition > originalPosition) Then
parentNode.InsertAfter(originalNode, newNode)
Else
parentNode.InsertBefore(originalNode, newNode)
End If
returnValue = newPosition
' Save the presentation XML back to its part.
doc.Save(presentationPart.GetStream)
End If
End If
End If
End If
End If
End If
Return returnValue
End Function
public static int PPTReorderSlides(string fileName, int originalPosition, int newPosition)
{
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
int returnValue = -1;
using (PresentationDocument pptPackage = PresentationDocument.Open(fileName, true))
{
PresentationPart presentationPart = pptPackage.PresentationPart;
if (presentationPart != null)
{
XmlDocument doc = new XmlDocument();
doc.Load(presentationPart.GetStream());
// Manage namespaces to perform XPath queries.
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("p", presentationmlNamespace);
XmlNodeList nodes = doc.SelectNodes("//p:sldId", nsManager);
if (nodes != null)
{
int slideCount = nodes.Count;
int maxPosition = slideCount;
if (slideCount > 0)
{
if (originalPosition == -1)
{
originalPosition = maxPosition;
}
if (newPosition == -1)
{
newPosition = maxPosition;
}
if (originalPosition > maxPosition)
{
originalPosition = maxPosition;
}
if (newPosition > maxPosition)
{
newPosition = maxPosition;
}
if (originalPosition < 0 || newPosition < 0)
{
// Something is wrong. Raise an exception.
throw new ArgumentException("Invalid parameter. Both original and new positions must be integers between -1 and the total number of slides.");
}
if (originalPosition != newPosition)
{
XmlNode parentNode = doc.SelectSingleNode("//p:sldIdLst", nsManager);
if (parentNode != null)
{
XmlNode originalNode = null;
XmlNode newNode = null;
string nodeSearch = null;
XmlAttribute attr = nodes[originalPosition - 1].Attributes["id"];
if (attr != null)
{
nodeSearch = string.Format("./p:sldId[@id='{0}']", attr.Value);
originalNode = parentNode.SelectSingleNode(nodeSearch, nsManager);
}
attr = nodes[newPosition - 1].Attributes["id"];
if (attr != null)
{
nodeSearch = string.Format("./p:sldId[@id='{0}']", attr.Value);
newNode = parentNode.SelectSingleNode(nodeSearch, nsManager);
}
if (originalNode != null && newNode != null)
{
if (newPosition > originalPosition)
{
parentNode.InsertAfter(originalNode, newNode);
}
else
{
parentNode.InsertBefore(originalNode, newNode);
}
returnValue = newPosition;
doc.Save(presentationPart.GetStream());
}
}
}
}
}
}
}
return returnValue;
}
이 프로시저에서는 PowerPoint 2007 문서에의 전체 경로, 대상 슬라이드의 현재위치를 보이는 서수 값,
슬라이드의 새로운 위치인 세가지 매개 변수를 전달합니다. 다음은PresentationDocument
개체의 Open 메서드를 사용하여 문서를 엽니다. 주 프레젠테이션 파트의 내용을 검색합니다. 또한 XmlNamespaceManager
개체를 사용하여 네임 스페이스 관리자를 설정합니다. p 수식자를 사용하여 기본값의 presentationml
네임 스페이스 참조를 설정합니다. 주 프레젠테이션 파트를 검색하여 프레젠테이션 슬라이드에의 참조를 포함하여 //p:sldId
노드를 선택합니다. 다음은 슬라이드의 위치를 검색합니다.
메모
: |
|
슬라이드의 지정된 현재위치가 데크의 슬라이드수의 범위를 넘는 경우, 마지막의 슬라이드가
사용됩니다. 새로운 위치가 슬라이드수의 범위를 넘는 경우, 선택한 슬라이드는 데크의
마지막 위치에 삽입됩니다.
|
다음은 최초로 데크의 슬라이드 수를 검색하여 호출자의 의도를 판단합니다. 원래의 위치 또는 목적의 위치를
나타내는 값이 슬라이드 수보다 큰 경우, 한쪽 또는 양쪽 모두를 마지막 슬라이드 위치로 설정합니다. 그
이외의 경우, 슬라이드에 대응하는 노드를 검색하여 바꿉니다. 마지막으로 프레젠테이션 XML 를 원본 파트에
저장합니다.
슬라이드의 이미지 바꾸기
다음 코드에서는 슬라이드의 첫번째 이미지 (존재하는 경우)를 외부파일 이미지로 바꿉니다.
Public Sub PPTReplaceImageOnSlide(ByVal fileName As String, ByVal slideTitle As String, ByVal imagePath As String)
Const presentationmlNamespace As String = "http://schemas.openxmlformats.org/presentationml/2006/main"
Const drawingmlNamespace As String = "http://schemas.openxmlformats.org/drawingml/2006/main"
Const relationshipNamespace As String = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
Dim pptPackage As PresentationDocument = PresentationDocument.Open(fileName, True)
Using (pptPackage)
Dim presentationPart As PresentationPart = pptPackage.PresentationPart
' Manage namespaces to perform Xml XPath queries.
Dim nt As NameTable = New NameTable
Dim nsManager As XmlNamespaceManager = New XmlNamespaceManager(nt)
nsManager.AddNamespace("p", presentationmlNamespace)
nsManager.AddNamespace("a", drawingmlNamespace)
nsManager.AddNamespace("r", relationshipNamespace)
Dim slideParts As List(Of SlidePart) = New List(Of SlidePart)()
presentationPart.GetPartsOfType(Of SlidePart)(slideParts)
For Each slidePart As SlidePart In slideParts
Dim slideDoc As XmlDocument = New XmlDocument(nt)
slideDoc.Load(slidePart.GetStream)
Dim titleNode As XmlNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager)
If (Not (titleNode) Is Nothing) Then
Dim titleText As String = titleNode.ParentNode.ParentNode.ParentNode.InnerText
If (String.Compare(titleText, slideTitle, True) = 0) Then
Dim imageParts As List(Of ImagePart) = New List(Of ImagePart)()
slidePart.GetPartsOfType(Of ImagePart)(imageParts)
For Each imagePart As ImagePart In imageParts
If (Not (imagePart) Is Nothing) Then
Dim oldRelID As String = slidePart.GetIdOfPart(imagePart)
Dim imageFile As String = Path.GetFileName(imagePath)
Dim newImageUri As Uri = New Uri(("/ppt/media/" + imageFile), UriKind.Relative)
Dim newImagePart As ImagePart = slidePart.AddImagePart(ImagePartType.Jpeg)
Dim outputStream As Stream = newImagePart.GetStream
Dim inputStream As FileStream = New FileStream(imagePath, FileMode.Open, FileAccess.Read)
Dim len As Integer = Convert.ToInt32(inputStream.Length)
Dim bytes() As Byte = New Byte((len) - 1) {}
Dim bytesRead As Integer = inputStream.Read(bytes, 0, len)
If (bytesRead = len) Then
outputStream.Write(bytes, 0, len)
End If
Dim searchString As String = String.Format("//p:pic//a:blip[@r:embed='{0}']", oldRelID)
Dim relNode As XmlNode = slideDoc.SelectSingleNode(searchString, nsManager)
If (Not (relNode) Is Nothing) Then
relNode.Attributes("r:embed").Value = slidePart.GetIdOfPart(newImagePart)
End If
slidePart.DeletePart(imagePart)
End If
Next
' Reset the stream, and save the slide XML back to its part.
slideDoc.Save(slidePart.GetStream)
End If
End If
Next
End Using
End Sub
public static void PPTReplaceImageOnSlide(string fileName, string slideTitle, string imagePath)
{
const string presentationmlNamespace = "http://schemas.openxmlformats.org/presentationml/2006/main";
const string drawingmlNamespace = "http://schemas.openxmlformats.org/drawingml/2006/main";
const string relationshipNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
using (PresentationDocument pptPackage = PresentationDocument.Open(fileName, true))
{
PresentationPart presentationPart = pptPackage.PresentationPart;
// Manage namespaces to perform Xml XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("p", presentationmlNamespace);
nsManager.AddNamespace("a", drawingmlNamespace);
nsManager.AddNamespace("r", relationshipNamespace);
List<SlidePart> slideParts = new List<SlidePart>();
presentationPart.GetPartsOfType<SlidePart>(slideParts);
foreach (SlidePart slidePart in slideParts)
{
XmlDocument slideDoc = new XmlDocument(nt);
slideDoc.Load(slidePart.GetStream());
XmlNode titleNode = slideDoc.SelectSingleNode("//p:sp//p:ph[@type='title' or @type='ctrTitle']", nsManager);
if (titleNode != null)
{
string titleText = titleNode.ParentNode.ParentNode.ParentNode.InnerText;
if (string.Compare(titleText, slideTitle, true) == 0)
{
List<ImagePart> imageParts = new List<ImagePart>();
slidePart.GetPartsOfType<ImagePart>(imageParts);
foreach (ImagePart imagePart in imageParts)
{
if (imagePart != null)
{
string oldRelID = slidePart.GetIdOfPart(imagePart);
string imageFile = Path.GetFileName(imagePath);
Uri newImageUri = new Uri("/ppt/media/" + imageFile, UriKind.Relative);
ImagePart newImagePart = slidePart.AddImagePart(ImagePartType.Jpeg);
using (Stream outputStream = newImagePart.GetStream())
{
using (FileStream inputStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
int len = Convert.ToInt32(inputStream.Length);
byte[] bytes = new byte[len];
int bytesRead = inputStream.Read(bytes, 0, len);
if (bytesRead == len)
{
outputStream.Write(bytes, 0, len);
}
}
}
string searchString = string.Format("//p:pic//a:blip[@r:embed='{0}']", oldRelID);
XmlNode relNode = slideDoc.SelectSingleNode(searchString, nsManager);
if (relNode != null)
{
relNode.Attributes["r:embed"].Value = slidePart.GetIdOfPart(newImagePart);
}
slidePart.DeletePart(imagePart);
break;
}
}
slideDoc.Save(slidePart.GetStream());
break;
}
}
}
}
}
이 프로시저에서는 PowerPoint 2007 문서에의 전체 경로, 대상 슬라이드 제목, 새로운 이미지가 포함된
파일의 전체 경로인 세가지 매개 변수를 전달합니다. 다음은 PresentationDocument 개체의 Open
메서드를 사용하여 문서를 엽니다. 주 프레젠테이션의 내용을 검색합니다. 또한 XmlNamespaceManager
개체를 사용하여 네임 스페이스 관리자를 설정합니다. p 수식자를 사용하여 기본값의 presentationml
네임 스페이스 참조를 a 수식자를 사용하여 drawingmlNamespace 네임 스페이스 참조를 r
수식자를 사용하여 relationshipNamespace 네임 스페이스 참조를
설정합니다. //p:sp//p:ph 노드의 title 특성 또는 ctrTitle
특성을 사용하여 각 슬라이드 제목 검색합니다.
다음은 슬라이드 파트에서 검색한 제목과 프로시저에게 건네진 슬라이드 제목을 비교합니다. 지정된 슬라이드가
발견되었을 경우는 그 슬라이드 파트를 변경해야 합니다. 우선, 슬라이드의 관계를 조사해 이미지가 존재할지를
확인합니다. 이미지가 존재하는 경우, 새로운 이미지를 위한 파트를 생성하여, 그 새로운 파트에 이미지를 복사 합니다.
다음은 슬라이드 파트의 관계를 업데이트하여 오랜 관계를 삭제합니다.
메모
: |
|
다음에 패키지 파일을 저장 했을 때에 고립한 이미지 파트가 삭제됩니다.
|
마지막으로 슬라이드 XML 를 원본 파트에 저장합니다.
요약
「Microsoft SDK for Open XML Formats 기술 프리뷰」를 참조하여, Excel 2007 및 PowerPoint 2007 파일 작업 매우 간단합니다. 이 문서의 프로시저를 사용하고 테스트를 실시하거나 실제
사용 목적에 맞추어 변경할 수도 있습니다. Excel 파일 및 PowerPoint 파일을 프로그램 위에서 조작하는 방법의 자세한 내용은 「Open XML 개체 모델을 사용한 Excel 2007 파일 및 PowerPoint 2007 파일 작업 (파트 1/2)」를 참조해 주세요.