[Blog Map] This blog is inactive. New blog: EricWhite.com/blog
On a fairly regular basis, I need to write an example that retrieves an Open XML document from a SharePoint document library, modify the document, and save the document back to the document library. The correct approach is to use a CAML query to retrieve the document. This post presents the minimum amount of code to use the SharePoint object model to do this.
This code requires the Open XML SDK, so you will need to download and install it. You need to add a reference to the assembly. In addition, you need to add a reference to the WindowsBase assembly and the Microsoft.SharePoint assembly.
See the Open XML Developer Center for lots of information on building applications that work with Open XML documents.
When building console applications for SharePoint 2010, you must target the .NET 3.5 framework. In addition, you must target ‘Any CPU’, not X86. The post Developing with SharePoint 2010 Word Automation Services contains explicit instructions for targeting .NET 3.5 and Any CPU.
Here is the smallest C# console application to do this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.SharePoint;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
classProgram
{
staticvoid Main(string[] args)
{
string siteUrl = "http://localhost";
using (SPSite spSite = newSPSite(siteUrl))
{
Console.WriteLine("Querying for Test.docx");
SPList list = spSite.RootWeb.Lists["Shared Documents"];
SPQuery query = newSPQuery();
query.ViewFields = @"<FieldRef Name='FileLeafRef' />";
query.Query =
@"<Where>
<Eq>
<FieldRef Name='FileLeafRef' />
<Value Type='Text'>Test.docx</Value>
</Eq>
</Where>";
SPListItemCollection collection = list.GetItems(query);
if (collection.Count != 1)
{
Console.WriteLine("Test.docx not found");
Environment.Exit(0);
}
Console.WriteLine("Opening");
SPFile file = collection[0].File;
byte[] byteArray = file.OpenBinary();
using (MemoryStream memStr = newMemoryStream())
{
memStr.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument wordDoc =
WordprocessingDocument.Open(memStr, true))
{
Document document = wordDoc.MainDocumentPart.Document;
Paragraph firstParagraph = document.Body.Elements<Paragraph>()
.FirstOrDefault();
if (firstParagraph != null)
{
Paragraph testParagraph = newParagraph(
newRun(
newText("Test")));
firstParagraph.Parent.InsertBefore(testParagraph,
firstParagraph);
}
}
Console.WriteLine("Saving");
string linkFileName = file.Item["LinkFilename"] asstring;
file.ParentFolder.Files.Add(linkFileName, memStr, true);
}
}
}
}
Here is the same example in VB. One thing that is cool about VB is that you can use XML literals to write the CAML query, and then call ToString() to set the Query field of the SPQuery object.
Imports System.IO
Imports System.Threading
Imports Microsoft.SharePoint
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Wordprocessing
ModuleModule1
Sub Main()
Dim siteUrl AsString = "http://localhost"
Using spSite AsSPSite = NewSPSite(siteUrl)
Console.WriteLine("Querying for Test.docx")
Dim list AsSPList = spSite.RootWeb.Lists("Shared Documents")
Dim query AsSPQuery = NewSPQuery()
query.ViewFields = "<FieldRef Name='FileLeafRef' />"
query.Query = ( _
<Where>
<Eq>
<FieldRefName='FileLeafRef'/>
<ValueType='Text'>Test.docx</Value>
</Eq>
</Where>).ToString()
Dim collection AsSPListItemCollection = list.GetItems(query)
If collection.Count <> 1 Then
Console.WriteLine("Test.docx not found")
Environment.Exit(0)
EndIf
Console.WriteLine("Opening")
Dim file AsSPFile = collection(0).File
Dim byteArray AsByte() = file.OpenBinary()
Using memStr AsMemoryStream = NewMemoryStream()
memStr.Write(byteArray, 0, byteArray.Length)
Using wordDoc AsWordprocessingDocument = _
WordprocessingDocument.Open(memStr, True)
Dim document AsDocument = wordDoc.MainDocumentPart.Document
Dim firstParagraph AsParagraph = _
document.Body.Elements(OfParagraph)().FirstOrDefault()
If firstParagraph IsNotNothingThen
Dim testParagraph AsParagraph = NewParagraph( _
NewRun( _
NewText("Test")))
firstParagraph.Parent.InsertBefore(testParagraph, _
firstParagraph)
EndIf
EndUsing
Console.WriteLine("Saving")
Dim linkFileName AsString = file.Item("LinkFilename")
file.ParentFolder.Files.Add(linkFileName, memStr, True)
EndUsing
EndUsing
EndSub
EndModule