Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010 mit Open XML SDK 2.0

Zusammenfassung: Mit dem verwalteten Clientobjektmodell von Microsoft SharePoint Foundation 2010 können Sie Anwendungen schreiben, die auf Microsoft .NET Framework basieren und auf SharePoint-Inhalte von Clients zugreifen, ohne Code auf dem Server mit SharePoint Foundation 2010 zu installieren. Sie können mit Open XML SDK 2.0 für Microsoft Office Anwendungen schreiben, um Open XML-Dokumente zu erstellen, zu ändern und abzufragen. Open XML ist das Standarddokumentformat für 2007 Microsoft Office System und Microsoft Office 2010. Wenn Sie diese beiden Technologien gemeinsam verwenden, können Sie clientseitige Anwendungen schreiben, die für in Dokumentbibliotheken gespeicherte Open XML-Dokumente verwendet werden können.

Letzte Änderung: Freitag, 4. November 2011

Gilt für: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Inhalt dieses Artikels
Übersicht
Abrufen von Dokumenten aus Dokumentbibliotheken
Ändern von Dokumenten in Dokumentbibliotheken
Hochladen von Dokumenten in Dokumentbibliotheken
Erstellen von Dokumenten im Arbeitsspeicher und Hinzufügen dieser Dokumente zu Dokumentbibliotheken
Verarbeiten aller Dokumente in einer Bibliothek
Erstellen von Textverarbeitungsdokumenten im Open XML-Format aus Wiki-Bibliotheken
Schlussbemerkung
Weitere Ressourcen

Bereitgestellt von: Eric White, Microsoft Corporation

Inhalt

  • Übersicht

  • Abrufen von Dokumenten aus Dokumentbibliotheken

  • Ändern von Dokumenten in Dokumentbibliotheken

  • Hochladen von Dokumenten in Dokumentbibliotheken

  • Erstellen von Dokumenten im Arbeitsspeicher und Hinzufügen dieser Dokumente zu Dokumentbibliotheken

  • Verarbeiten aller Dokumente in einer Bibliothek

  • Erstellen von Textverarbeitungsdokumenten im Open XML-Format aus Wiki-Bibliotheken

  • Schlussbemerkung

  • Weitere Ressourcen

Übersicht

Das verwaltete Clientobjektmodell von Microsoft SharePoint Foundation 2010 besteht aus einem Satz verwalteter Bibliotheken, die auf Microsoft .NET Framework basieren und mit denen Sie Code für Clientcomputer schreiben können, der für viele der allgemeinen Objekte auf SharePoint-Websites verwendet werden kann. Mit den auf dem Client ausgeführten Programmen können Sie Listen hingefügen und entfernen, Listenelemente hinzufügen, aktualisieren und löschen, Dokumente in Dokumentbibliotheken ändern, Websites erstellten, Berechtigungen für Elemente verwalten und Webparts auf Seiten hinzufügen oder entfernen.

Das Open XML-Dateiformat (das Dokumentformat für Microsoft Office 2007 und Office 2010) ist ein ISO/IEC-Standard (IS29500), in dem die wesentlichen Eigenschaften von Textverarbeitungs-, Tabellenkalkulations- und Präsentationsdokumenten beschrieben werden. Dateien im Open XML-Format werden gemäß den in den Open Packaging-Konventionen definierten Regeln (Teil 2 von IS29500) gespeichert. Es handelt sich im Grunde um ZIP-Dateien, die XML-Komponenten enthalten. Open XML SDK 2.0 für Microsoft Office ist eine verwaltete Bibliothek, die auf .NET Framework basiert. Daher können Sie leicht Programme schreiben, um Open XML-Dokumente zu erstellen, zu ändern oder abzufragen. Am Ende dieses Artikels finden Sie eine Liste mit Ressourcen, die Ihnen bei den ersten Schritten mit Open XML SDK 2.0 helfen sollen.

Durch die gemeinsame Verwendung dieser beiden Technologien ergeben sich interessante Szenarien:

  • Sie können eine clientseitige Anwendung schreiben, durch die ein Textverarbeitungsdokument oder eine Präsentation mit von einer anderen Stelle abgerufenen Inhalten erstellt wird. Das Dokument wird dann automatisch in eine Dokumentbibliothek auf einer SharePoint-Website hochgeladen.

  • Sie können eine Anwendung schreiben, um alle Dokumente in einer Dokumentbibliothek abzufragen und dabei Informationen aus den einzelnen Dokumenten zu extrahieren.

  • Sie können eine Anwendung schreiben, um alle Dokumente in einer Dokumentbibliothek zu verarbeiten und an allen die gleichen Änderungen vorzunehmen. Eine interessante Möglichkeit ist dabei, dass Sie in jedem einzelnen Dokument in der Dokumentbibliothek alle Kommentare und persönlichen Informationen entfernen und alle nachverfolgten Änderungen akzeptieren können.

  • Sie können den Inhalt einer Wiki-Site extrahieren und daraus ein Open XML-Dokument erstellen.

Dieser Artikel basiert auf den Informationen in Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010. Weitere Informationen zur Funktionsweise des verwalteten Clientobjektmodells von SharePoint Foundation 2010 finden Sie dort.

Abrufen von Dokumenten aus Dokumentbibliotheken

Wenn Sie mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 und Open XML-Formaten arbeiten, führen Sie zwei Standardvorgänge aus: Abrufen von Dokumenten und Speichern von Dokumenten. Im folgenden Beispiel wird ein Dokument aus einer Dokumentbibliothek abgerufen und der Text des ersten Absatzes gedruckt.

HinweisHinweis

In diesem Artikel werden für den Beispielcode Microsoft Windows-Konsolenanwendungen verwendet. Sie können die gleiche Methode jedoch auch für andere Anwendungstypen verwenden.

Zum Erstellen des Beispiels müssen Sie Verweise auf vier Assemblys hinzufügen. Zwei Assemblys werden für den Zugriff auf das verwaltete Clientobjektmodell von SharePoint Foundation 2010 benötigt: Microsoft.SharePoint.Client.dll und Microsoft.SharePoint.Client.Runtime.dll. Zwei Assemblys werden für die Verwendung von Open XML SDK 2.0 benötigt: DocumentFormat.OpenXml.dll und WindowsBase.dll. Detaillierte Anweisungen zum Erstellen einer Konsolenanwendung, in der das verwaltete Clientobjektmodell von SharePoint Foundation 2010 verwendet wird, finden Sie unter Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010.

Zum Erstellen der in diesem Artikel beschriebenen Beispiele müssen Sie außerdem Open XML SDK 2.0 herunterladen und installieren. Detaillierte Anweisungen zum Erstellen von Open XML SDK 2.0-Anwendungen finden Sie unter Willkommen beim Open XML SDK 2.0 für Microsoft Office. Open XML SDK 2.0 können Sie unter Open XML SDK 2.0 herunterladen.

using System;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.SharePoint.Client;
// The following using directive resolves the ambiguity
// between the System.IO.File class and Microsoft.SharePoint.Client.File
// class.
using ClientOM = Microsoft.SharePoint.Client;

class Program
{
    static private void CopyStream(Stream source, Stream destination)
    {
        byte[] buffer = new byte[32768];
        int bytesRead;
        do
        {
            bytesRead = source.Read(buffer, 0, buffer.Length);
            destination.Write(buffer, 0, bytesRead);
        } while (bytesRead != 0);
    }

    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List sharedDocumentsList = clientContext.Web.Lists
            .GetByTitle("Shared Documents");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='FileLeafRef'/>
                      <Value Type='Text'>Test.docx</Value>
                    </Eq>
                  </Where>
                  <RowLimit>1</RowLimit>
                </Query>
              </View>";
        ListItemCollection listItems = sharedDocumentsList.GetItems(camlQuery);
        clientContext.Load(sharedDocumentsList);
        clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        if (listItems.Count == 1)
        {
            ClientOM.ListItem item = listItems[0];
            Console.WriteLine("FileLeafRef: {0}", item["FileLeafRef"]);
            Console.WriteLine("FileDirRef: {0}", item["FileDirRef"]);
            Console.WriteLine("FileRef: {0}", item["FileRef"]);
            Console.WriteLine("File Type: {0}", item["File_x0020_Type"]);
            FileInformation fileInformation =
                ClientOM.File.OpenBinaryDirect(clientContext, (string)item["FileRef"]);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                CopyStream(fileInformation.Stream, memoryStream);
                using (WordprocessingDocument doc =
                    WordprocessingDocument.Open(memoryStream, false))
                {
                    var firstParagraph = doc
                        .MainDocumentPart
                        .Document
                        .Body
                        .Elements<Paragraph>()
                        .FirstOrDefault();
                    if (firstParagraph != null)
                    {
                        string text = firstParagraph.InnerText;
                        Console.WriteLine(text);
                    }
                    else
                        Console.WriteLine("Document doesn't contain any paragraphs.");
                }
            }
        }
        else
            Console.WriteLine("Document not found.");
    }
}

In diesem Beispiel wird eine Ausgabe erzeugt, die ungefähr wie folgt aussieht.

FileLeafRef: Test.docx
FileDirRef: /Shared Documents
FileRef: /Shared Documents/Test.docx
File Type: docx
This is the text of the first paragraph.

In diesem Beispiel werden die Felder gedruckt, die Sie oft verwenden, wenn Sie mit Dokumenten in Dokumentbibliotheken arbeiten:

  • Das FileLeafRef-Feld enthält den Namen der Datei.

  • Das FileDirRef-Feld enthält den Namen der Dokumentbibliothek. Wenn sich die Datei in einem Ordner befindet, enthält das FileDirRef-Feld außerdem den Ordnernamen.

  • Das FileRef-Feld enthält den vollständigen Namen. Dazu gehören der Name der Dokumentbibliothek, Ordner und der Dateiname.

Mit der CAML-Abfrage wird nach einem Element in der Dokumentbibliothek gesucht, dessen FileLeafRef-Feld den Wert Test.docxaufweist, und das RowLimit-Element des View-Elements wird auf 1 festgelegt.

camlQuery.ViewXml =
    @"<View>
        <Query>
          <Where>
            <Eq>
              <FieldRef Name='FileLeafRef'/>
              <Value Type='Text'>Test.docx</Value>
            </Eq>
          </Where>
          <RowLimit>1</RowLimit>
        </Query>
      </View>";

Da im Beispiel das RowLimit-Element auf 1 festgelegt wird, gibt die Abfrage ein ListItemCollection-Objekt zurück, dass entweder keine Elemente oder ein Element enthält. Daher können Sie die Funktionalität testen, indem Sie mit listItems.Count == 1 ermitteln, ob das Dokument von der Abfrage gefunden wird.

Zum Abrufen der Datei wird die OpenBinaryDirect()-Methode verwendet, um ein Objekt vom Typ FileInformation zurückzugeben.

FileInformation fileInformation =
    ClientOM.File.OpenBinaryDirect(clientContext, (string)item["FileRef"]);

Das FileInformation-Objekt enthält einen Verweis auf einen Datenstrom, den Sie verwenden können, um die Datei an die Anwendung zu streamen. Die Größe dieses Datenstroms ist jedoch nicht veränderbar. Für die Open()-Methode der WordprocessingDocument-Klasse kann ein Datenstrom als Argument verwendet werden. Dabei muss die Größe des Datenstroms jedoch veränderbar sein. Daher müssen Sie ein MemoryStream-Objekt erstellen und dieses dann aus dem von der Stream-Eigenschaft zurückgegebenen Objekt in das MemoryStream-Objekt kopieren. Beim Versuch, das WordprocessingDocument-Objekt aus dem von der Stream-Eigenschaft zurückgegebenen Datenstrom zu öffnen, wird durch die Open()-Methode die Ausnahme System.IO.IOException ausgelöst. Die Meldung lautet "Das Paket kann nicht geöffnet werden, weil der FileMode- oder FileAccess-Wert nicht für den Datenstrom gültig ist".

Möglicherweise haben Sie bemerkt, dass es nicht notwendig war, die ExecuteQuery()-Methode vor dem Zugriff auf die Stream-Eigenschaft aufzurufen. Das liegt daran, dass die OpenBinaryDirect()-Methode nicht an der normalen XML/JSON-Netzwerkkommunikation des Clientobjektmodells beteiligt ist. Im Artikel Using the SharePoint Foundation 2010 Managed Client Object Model wird erläutert, wie die Clientkomponente des Clientobjektmodells Anforderungen als XML bündelt. Die XML-Daten werden an den Server gesendet, von dem die Anforderungen verarbeitet werden. Anschließend wird die Antwort in JSON gesendet. Wenn Sie Dateien mit XML und JSON hochladen, wird das binäre Dokument im Open XML-Format vom Clientobjektmodell mit Base-64 codiert. Die Verwendung dieser Codierung ist jedoch weniger effizient als das direkte Senden der Binärdaten. Es wird empfohlen, Binärdaten nach Möglichkeit direkt zu senden. Dadurch ergibt sich eine effizientere Anwendung, und der Datenverkehr im Netzwerk wird reduziert.

Anschließend haben Sie ein MemoryStream-Objekt, dessen Größe geändert werden kann, wenn das Objekt mithilfe des Konstruktors erstellt wurde, für den keine Parameter verwendet werden können. Dann öffnen Sie das Dokument mithilfe der Open()-Methode und verarbeiten das Dokument wie gewohnt.

VorsichtVorsicht

Die MemoryStream-Klasse enthält einen Konstruktor, für den ein Bytearray verwendet werden kann, das dann als Sicherheitskopie für den Datenstrom verwendet wird. Der Konstruktor gibt jedoch einen Speicherstream mit nicht veränderbarer Größe zurück. Daher können Sie diesen Konstruktor nicht verwenden, um einen Speicherstream für die Verwendung mit der Open XML-API zu erstellen.

Ändern von Dokumenten in Dokumentbibliotheken

Sie können das vorherige Beispiel so ändern, dass das Dokument geändert und dann wieder in einer Dokumentbibliothek gespeichert wird.

using System;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;

class Program
{
    static private void CopyStream(Stream source, Stream destination)
    {
        byte[] buffer = new byte[32768];
        int bytesRead;
        do
        {
            bytesRead = source.Read(buffer, 0, buffer.Length);
            destination.Write(buffer, 0, bytesRead);
        } while (bytesRead != 0);
    }

    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List sharedDocumentsList = clientContext.Web.Lists
            .GetByTitle("Shared Documents");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='FileLeafRef'/>
                      <Value Type='Text'>Test.docx</Value>
                    </Eq>
                  </Where>
                  <RowLimit>1</RowLimit>
                </Query>
              </View>";
        ListItemCollection listItems =
            sharedDocumentsList.GetItems(camlQuery);
        clientContext.Load(sharedDocumentsList);
        clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        if (listItems.Count == 1)
        {
            ClientOM.ListItem item = listItems[0];
            Console.WriteLine("FileLeafRef: {0}", item["FileLeafRef"]);
            Console.WriteLine("FileDirRef: {0}", item["FileDirRef"]);
            Console.WriteLine("FileRef: {0}", item["FileRef"]);
            Console.WriteLine("File Type: {0}", item["File_x0020_Type"]);
            FileInformation fileInformation =
                ClientOM.File.OpenBinaryDirect(clientContext,
                (string)item["FileRef"]);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                CopyStream(fileInformation.Stream, memoryStream);
                using (WordprocessingDocument doc =
                    WordprocessingDocument.Open(memoryStream, true))
                {
                    // Insert a new paragraph at the beginning of the
                    //document.
                    doc.MainDocumentPart.Document.Body.InsertAt(new Paragraph(new Run(new Text("Newly inserted paragraph."))), 0);
                }
                // Seek to beginning before writing to the SharePoint server.
                memoryStream.Seek(0, SeekOrigin.Begin);
                // SaveBinaryDirect replaces the document on the SharePoint server.
                ClientOM.File.SaveBinaryDirect(clientContext,(string)item["FileRef"], memoryStream, true);
            }
        }
        else
            Console.WriteLine("Document not found.");
    }
}

Beachten Sie, dass in diesem Beispiel der Wert true an die Open()-Methode übergeben wurde, sodass Sie das Dokument ändern können. Wenn Sie das Dokument mithilfe der Open()-Methode geöffnet haben, können Sie das Dokument wie gewohnt ändern.

Wenn Sie den Bereich verlassen haben, der durch die Anweisung zum Öffnen des Dokuments durch Aufrufen der Open()-Methode erstellt wurde, enthält das MemoryStream-Objekt das geänderte Dokument. Bevor Sie das Dokument zurück an den Server streamen können, müssen Sie den Anfang des Datenstroms suchen. Dann rufen Sie die SaveBinaryDirect()-Methode auf, durch die das geänderte Dokument wieder in der Dokumentbibliothek gespeichert wird.

Hochladen von Dokumenten in Dokumentbibliotheken

Mit dem nächsten Vorgang werden vorhandene Dokumente in eine Dokumentbibliothek hochgeladen. Sie können ein Dokument hochladen, indem Sie die SaveBinaryDirect()-Methode aufrufen und die serverrelative URL und einen Datenstrom übergeben. Im folgenden Beispiel wird ein neues Dokument in den Ordner Freigegebene Dokumente einer SharePoint-Website hochgeladen.

using System;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.SharePoint.Client;
// The following directive avoids ambiguity between the
// System.IO.File class and Microsoft.SharePoint.Client.File class.
using ClientOM = Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        using (FileStream fileStream =
            new FileStream("NewDocument.docx", FileMode.Open))
            ClientOM.File.SaveBinaryDirect(clientContext,
                "/Shared Documents/NewDocument.docx", fileStream, true);
    }
}

Erstellen von Dokumenten im Arbeitsspeicher und Hinzufügen dieser Dokumente zu Dokumentbibliotheken

Es gibt zwei allgemeine Methoden zum Erstellen von Dokumenten mithilfe der API für Open XML-Formate:

  • Verwenden Sie ein vorhandenes Dokument als Vorlage, öffnen Sie das Dokument, nehmen Sie die gewünschten Änderungen vor, und speichern Sie das Dokument am gewünschten Speicherort.

  • Erstellen Sie ein Dokument. Häufig verwenden Sie hierzu das DocumentReflector-Tool aus Open XML SDK 2.0 für Microsoft Office. Mit diesem Tool können Sie den Microsoft Visual C#-Code zum Erstellen eines beliebigen Dokuments im Open XML-Format generieren.

In beiden Fällen können Sie das Dokument in einem MemoryStream-Objekt erstellen. Im folgenden Beispiel wird ein Dokument in ein Bytearray gelesen, dann wird mithilfe des MemoryStream-Konstruktors, für den keine Argumente verwendet werden können, ein Speicherstream mit veränderbarer Größe erstellt. Das Bytearray wird in MemoryStream geschrieben, das Dokument wird im Arbeitsspeicher geändert, und anschließend wird das geänderte Dokument in die Bibliothek Freigegebene Dokumente einer SharePoint-Website hochgeladen.

Zum Ausführen dieses Beispiels erstellen Sie ein Textverarbeitungsdokument mit dem Namen Template.docx, initialisieren das Dokument mit einem beliebigen Inhalt (oder auch ganz ohne Inhalt) und speichern das Dokument im Verzeichnis "bin", in dem Sie das Beispiel ausführen. Im Beispiel wird am Anfang des Dokuments ein neuer Absatz eingefügt, bevor das Dokument in die Dokumentbibliothek hochgeladen wird.

using System;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        byte[] byteArray = System.IO.File.ReadAllBytes("Template.docx");
        using (MemoryStream memoryStream = new MemoryStream())
        {
            memoryStream.Write(byteArray, 0, (int)byteArray.Length);
            using (WordprocessingDocument doc =
                WordprocessingDocument.Open(memoryStream, true))
            {
                // Insert a new paragraph at the beginning of the
                //document.
                doc.MainDocumentPart.Document.Body.InsertAt(
                    new Paragraph(
                        new Run(
                            new Text("Newly inserted paragraph."))), 0);
            }
            string fileUrl = "/Shared Documents/NewDocumentFromTemplate.docx";
            memoryStream.Seek(0, SeekOrigin.Begin);
            ClientOM.File.SaveBinaryDirect(clientContext, fileUrl, memoryStream, true);
        }
    }
}

Verarbeiten aller Dokumente in einer Bibliothek

Manchmal möchten Sie alle Dokumente in einer Dokumentbibliothek durchlaufen und dabei in allen Dokumenten die gleiche Abfrage ausführen oder die gleiche Änderung vornehmen. Die Dokumentbibliothek kann Ordner enthalten, die Dokumente und möglicherweise Unterordner enthalten. Im folgenden Beispiel wird gezeigt, wie Sie das Scope=’Recursive’-Attribut des View-Elements verwenden, um alle Dokumente in einer Dokumentbibliothek zu verarbeiten. Dazu gehören auch Dokumente in Unterordnern.

VorsichtVorsicht

Wenn Sie alle Dokumente in einer großen Dokumentbibliothek mit mehr als 2000 Dokumenten verarbeiten, müssen Sie einen Auslagerungsalgorithmus implementieren. Details hierzu finden Sie unter Using the SharePoint Foundation 2010 Managed Client Object Model. Wenn Sie hierfür eine interaktive Anwendung erstellen, können Sie asynchrone Verarbeitung verwenden. Weitere Informationen finden Sie unter Asynchrone Verarbeitung.

using System;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;

class Program
{
    static private void CopyStream(Stream source, Stream destination)
    {
        byte[] buffer = new byte[32768];
        int bytesRead;
        do
        {
            bytesRead = source.Read(buffer, 0, buffer.Length);
            destination.Write(buffer, 0, bytesRead);
        } while (bytesRead != 0);
    }

    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List sharedDocumentsList = clientContext.Web.Lists
            .GetByTitle("Shared Documents");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View Scope='Recursive'>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='File_x0020_Type'/><Value Type='Text'>docx</Value>
                    </Eq>
                  </Where>
                </Query>
              </View>";
        ListItemCollection listItems =
            sharedDocumentsList.GetItems(camlQuery);
        clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        foreach (var item in listItems)
        {
            Console.WriteLine("FileLeafRef: {0}", item["FileLeafRef"]);
            Console.WriteLine("FileDirRef: {0}", item["FileDirRef"]);
            Console.WriteLine("FileRef: {0}", item["FileRef"]);
            FileInformation fileInformation =
                ClientOM.File.OpenBinaryDirect(clientContext,
                (string)item["FileRef"]);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                CopyStream(fileInformation.Stream, memoryStream);
                using (WordprocessingDocument doc =
                    WordprocessingDocument.Open(memoryStream, true))
                {
                    var firstParagraph = doc.MainDocumentPart.Document
                        .Body.Elements<Paragraph>().FirstOrDefault();
                    if (firstParagraph != null)
                    {
                        string text = firstParagraph.InnerText;
                        Console.WriteLine("  First paragraph text: {0}",
                            text);
                    }
                    else
                        Console.WriteLine(
                            "Document doesn't contain any paragraphs.");
                }
            }
            Console.WriteLine();
        }
    }
}

Beim Verarbeiten aller Dokumente im Open XML-Format in einer Dokumentbibliothek oder einem Ordner empfiehlt sich die Verwendung einer CAML-Abfrage zum Filtern nach Dokumenten des gewünschten Dokumenttyps (in diesem Beispiel "DOCX"). Im hervorgehobenen Code in der Collaborative Application Markup Language (CAML)-Abfrage im Beispiel sehen Sie, wie Sie dazu vorgehen müssen.

Das Projekt PowerTools for Open XML enthält eine Bibliothek für alle nachverfolgten Überarbeitungen eines Textverarbeitungsdokuments. Durch eine einfache Änderung an diesem Beispiel können Sie ein Programm erstellen, mit dem alle Dokumente in einer Dokumentbibliothek durchlaufen und die Änderungen in allen Dokumenten akzeptiert werden. Die RevisionAccepter-Klasse finden Sie im Downloadbereich von PowerTools for Open XML.

Erstellen von Textverarbeitungsdokumenten im Open XML-Format aus Wiki-Bibliotheken

Die Verwendung der Open XML-API zusammen mit dem Clientobjektmodell fördert innovative Lösungen. Beispielsweise kann ein Wiki-Benutzer ein Dokument an Personen verteilen, die nicht über Zugriff auf die entsprechende Wiki-Website verfügen. Diese Personen können Kunden oder Zulieferer sein, die nicht über Zugriff auf das Unternehmensnetzwerk verfügen, aber die im Wiki enthaltenen Informationen benötigen. Sie können eine SharePoint-Wiki-Bibliothek in ein Dokument im Open XML-Format konvertieren, das Sie an jeden senden können, der über Microsoft Office Word 2007 oder Microsoft Word 2010 verfügt. In diesem Abschnitt wird gezeigt, wie Sie dies mithilfe des Clientobjektmodells erreichen.

Verwenden Sie hierzu die altChunk-Funktionen des Open XML-Formats. WordprocessingML ermöglicht das Importieren externer Inhalte über das altChunk-Element. Zum Verwenden von altChunk führen Sie die folgenden Schritte aus:

  • Sie erstellen eine zusätzliche Komponente im Paket. Die Komponente kann verschiedene Inhaltstypen aufweisen. Dazu gehören vollständige Dokumente im Open XML-Format, HTML oder Klartext. In diesem Beispiel verwenden Sie die Funktion zum Importieren von HTML.

  • Sie speichern die Inhalte, die Sie in die Komponente importieren möchten.

  • Beim Erstellen der Komponente erstellen Sie eine Beziehung zwischen dem Hauptdokumentteil der neuen alternativen Formatkomponente

  • Sie fügen ein w:altChunk-Element an der Stelle hinzu, an der Sie den alternativen Formatinhalt importieren möchten. Das r:id-Attribut des w:altChunk-Elements identifiziert den zu importierenden Inhalt. Beim w:altChunk-Element handelt es sich um einen Inhalt auf Blockebene, das heißt, Sie können den Inhalt überall dort in das Dokument einfügen, wo Sie ein Absatzelement (w:p) einfügen können.

    In diesem Beispiel wird der HTML-Code für die einzelnen Themen im Wiki extrahiert, und die einzelnen Seiten werden in eine eigene Komponente eingefügt. Dann werden die einzelnen Komponenten mithilfe des w:altChunk-Elements in das Dokument importiert.

Wichtiger HinweisWichtig

Wichtig ist bei altChunk, dass dieses Element nur zum Importieren von Inhalten verwendet wird. Wenn Sie das Dokument mit Word 2007 oder Word 2010 öffnen und speichern, enthält das neu gespeicherte Dokument weder die Inhaltskomponente mit dem alternativen Format noch das altChunk-Markup, in dem darauf verwiesen wird. Der HTML-Code wird von Word 2007 oder Word 2010 in "WordprocessingML"-Markup wie beispielsweise Absatzelemente (w:p), Ausführungselemente (w:r) und Textelemente (w:t) konvertiert.

Im nächsten Beispiel wird der Inhalt der einzelnen Wiki-Seiten als HTML extrahiert.

using System;
using System.Xml.Linq;
using Microsoft.SharePoint.Client;

class RetrieveListItems
{
    static void Main()
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List oList = clientContext.Web.Lists.GetByTitle("Eric's Wiki");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = @"<View/>";
        ListItemCollection listItems = oList.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["FileRef"],
                 item => item["WikiField"]));
        clientContext.ExecuteQuery();
        foreach (ListItem oListItem in listItems)
        {
            Console.WriteLine("FileRef: {0}", oListItem["FileRef"]);
            XElement e = XElement.Parse((string)oListItem["WikiField"]);
            Console.WriteLine(e);
            Console.WriteLine("====================================");
        }
    }
}

Als Nächstes ändern Sie die an den [M:Microsoft.SharePoint.Client.ClientContext.#Ctor]-Konstruktor übergebene URL in die URL der SharePoint-Website. Ändern Sie den an die GetByTitle()-Methode übergebenen Titel in den Titel einer Wiki-Bibliothek auf der SharePoint-Website.

In diesem Beispiel wird mithilfe von LINQ to XML der aus der Wiki-Bibliothek abgerufene XHTML-Code formatiert (eingerückt). Wenn Sie das Beispiel ausführen, wird beispielsweise Folgendes angezeigt.

FileRef: /Erics Wiki/AnotherPage.aspx
<div class="ExternalClass7EB3EF2C25AB481081BEE2BF8D80B6B8">
  <table id="layoutsTable" style="width:100%">
    <tbody>
      <tr style="vertical-align:top">
        <td style="width:100%">
          <div class="ms-rte-layoutszone-outer" style="width:100%"><div><p>This is some content in another page.</p><p> </p><p><strong>Here is some bold text.</strong></p><p></p></div></div>
        </td>
      </tr>
    </tbody>
  </table>

  <span id="layoutsData" style="display:none">false,false,1</span>
</div>
====================================
FileRef: /Erics Wiki/This is a longer title of a page.aspx
<div class="ExternalClass980D47DB1C51449E9684343F131C5689">
  <table id="layoutsTable" style="width:100%">
    <tbody>
      <tr style="vertical-align:top">
        <td style="width:100%">
          <div class="ms-rte-layoutszone-outer" style="width:100%"><div><p>This page contains some content we will extend in the future.</p><p></p></div></div>
        </td>
      </tr>
    </tbody>
  </table>

  <span id="layoutsData" style="display:none">false,false,1</span>
</div>

Wie Sie sehen, ist der Inhalt der einzelnen Seiten in der Wiki-Bibliothek in einem <div>-Element enthalten. Im <div>-Element befindet sich ein Tabellenelement, das vom Wiki für das Layout verwendet wird. Das für Sie interessante Element ist das <div>-Element in der Tabellenzelle, dessen Klassenattribut den Wert ms-rte-layoutszone-outerhat. Beim Erstellen des HTML-Codes, der in die Importkomponente mit alternativem Format eingefügt werden soll, fügen Sie das innere <div>-Element in das <body>-Element des HTML-Dokuments ein. Dann wird der neu erstellte HTML-Code in die alternative Inhaltskomponente geschrieben.

Hinweis zu Visual BasicVisual Basic-Hinweis

Bei dieser Konvertierung werden die Wiki-Links nicht in Textmarken und Links im Dokument konvertiert. Außerdem gibt es bestimmte Zeichen, die auf der Wiki-Seite eingefügt werden können, aber nicht richtig konvertiert werden. Es handelt sich hierbei um eine Prüfung des Konzepts, die die Möglichkeiten bei der Verwendung des Clientobjektmodells mit der API für das Open XML-Format zeigen soll. Die Konvertierung ist nicht als Lösung für alle Probleme im Zusammenhang mit der Konvertierung eines SharePoint-Wikis in ein Dokument im Open XML-Format gedacht.

In diesem Beispiel wird der Inhalt aller Seiten eines SharePoint-Wikis extrahiert und daraus ein Textverarbeitungsdokument erstellt.

using System;
using System.Linq;
using System.IO;
using System.Xml.Linq;
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

class RetrieveListItems
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List oList = clientContext.Web.Lists.GetByTitle("Eric's Wiki");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = @"<View/>";
        ListItemCollection listItems = oList.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["FileLeafRef"],
                 item => item["WikiField"]));
        clientContext.ExecuteQuery();

        System.IO.File.Delete("WikiDocument.docx");
        System.IO.File.Copy("EmptyDocument.docx", "WikiDocument.docx");
        int altChunkIdCounter = 1;
        int blockLevelCounter = 0;
        bool first = true;
        using (WordprocessingDocument myDoc =
            WordprocessingDocument.Open("WikiDocument.docx", true))
        {
            MainDocumentPart mainPart = myDoc.MainDocumentPart;
            mainPart.Document.Body.RemoveAllChildren<Paragraph>();
            foreach (ClientOM.ListItem listItem in listItems)
            {
                string wikiPageTitleAspx = (string)listItem["FileLeafRef"];
                string wikiPageTitle = wikiPageTitleAspx.Substring(
                    0, wikiPageTitleAspx.Length - 5);
                if (first)
                {
                    first = false;
                    mainPart.Document.Body.InsertAt(new Paragraph(
                        new ParagraphProperties(
                            new RunProperties(
                                new RunFonts() {
                                    AsciiTheme = ThemeFontValues.MajorHighAnsi,
                                    HighAnsiTheme = ThemeFontValues.MajorHighAnsi },
                                new Bold(),
                                new Color() { Val = "1F497D",
                                    ThemeColor = ThemeColorValues.Text2 },
                                new FontSize() { Val = 28 },
                                new FontSizeComplexScript() { Val = 28 }),
                            new ParagraphStyleId() { Val = "Heading1" }),
                        new Run(
                            new RunProperties(
                                new RunFonts() {
                                    AsciiTheme = ThemeFontValues.MajorHighAnsi,
                                    HighAnsiTheme = ThemeFontValues.MajorHighAnsi },
                                new Bold(),
                                new Color() { Val = "1F497D",
                                    ThemeColor = ThemeColorValues.Text2 },
                                new FontSize() { Val = 28 },
                                new FontSizeComplexScript() { Val = 28 }),
                            new Text(wikiPageTitle))),
                        blockLevelCounter++);
                }
                else
                {
                    mainPart.Document.Body.InsertAt(new Paragraph(
                        new Run(
                            new Break() { Type = BreakValues.Page } )),
                        blockLevelCounter++);
                    mainPart.Document.Body.InsertAt(new Paragraph(
                        new ParagraphProperties(
                            new RunProperties(
                                new RunFonts() {
                                    AsciiTheme = ThemeFontValues.MajorHighAnsi,
                                    HighAnsiTheme = ThemeFontValues.MajorHighAnsi },
                                new Bold(),
                                new Color() { Val = "1F497D",
                                    ThemeColor = ThemeColorValues.Text2 },
                                new FontSize() { Val = 28 },
                                new FontSizeComplexScript() { Val = 28 }),
                            new ParagraphStyleId() { Val = "Heading1" }),
                        new Run(
                            new RunProperties(
                                new RunFonts() {
                                    AsciiTheme = ThemeFontValues.MajorHighAnsi,
                                    HighAnsiTheme = ThemeFontValues.MajorHighAnsi },
                                new Bold(),
                                new Color() { Val = "1F497D",
                                    ThemeColor = ThemeColorValues.Text2 },
                                new FontSize() { Val = 28 },
                                new FontSizeComplexScript() { Val = 28 }),
                            new Text(wikiPageTitle))),
                        blockLevelCounter++);
                }
                XElement wikiField = XElement.Parse((string)listItem["WikiField"]);
                XElement div = wikiField.Descendants("div").Where(e =>
                    (string)e.Attribute("class") == "ms-rte-layoutszone-inner" )
                    .FirstOrDefault();
                string html = String.Format(
                    "<html><head/><body>{0}</body></html>",
                    div != null ? div.ToString() : "");
                string altChunkId = String.Format("AltChunkId{0}",
                    altChunkIdCounter++);
                AlternativeFormatImportPart chunk =
                    mainPart.AddAlternativeFormatImportPart(
                    AlternativeFormatImportPartType.Xhtml, altChunkId);
                using (Stream chunkStream = chunk.GetStream(FileMode.Create,
                    FileAccess.Write))
                using (StreamWriter stringStream = new StreamWriter(chunkStream))
                    stringStream.Write(html);
                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                mainPart.Document.Body.InsertAt(altChunk,
                    blockLevelCounter++);
            }
            mainPart.Document.Save();
        }
    }
}

 

Dieses Beispiel bietet umfangreiche Funktionalität mit weniger als 130 Codezeilen. Nachfolgend sehen Sie, wie eine der Seiten im SharePoint-Wiki angezeigt wird.

Abbildung 1. Seite in einer Wiki-Bibliothek

Abbildung 1

 

Die gleiche Seite in Word 2010 sieht wie folgt aus:

Abbildung 2. Gleiche Seite als Textverarbeitungsdokument im Open XML-Format

Abbildung 2

 

Schlussbemerkung

Mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 können Sie leistungsstarke clientseitige Anwendungen schreiben, die mit SharePoint Foundation 2010 und SharePoint Server 2010 verwendet werden können. Mit Open XML SDK 2.0 können Sie Dokumente im Open XML-Format erstellen, ändern und abfragen. Zusammen verwendet ergeben sich durch diese Kombination neue Möglichkeiten für die Verwendung von Open XML-Dokumenten für die Zusammenarbeit und den Informationsaustausch.

Weitere Ressourcen

In diesem Artikel werden zwei Technologien kombiniert: Open XML SDK 2.0 und das verwaltete Clientobjektmodell von SharePoint Foundation 2010. Für die ersten Schritte mit Open XML bietet sich das Open XML Developer Center auf MSDN an. Dort finden Sie vielfältige Inhalte. Dazu gehören Artikel, Gewusst-wie-Videos und Links zu zahlreichen Blogbeiträgen. Insbesondere die folgenden Links bieten wichtige Informationen für die ersten Schritte mit Open XML SDK 2.0:

Es gibt zahlreiche Ressourcen, die Sie bei den ersten Schritten mit dem verwalteten Clientobjektmodell von SharePoint Foundation 2010 unterstützen. Lesen Sie zuerst Verwenden des verwalteten Clientobjektmodells von SharePoint Foundation 2010. Die folgenden Ressourcen enthalten ebenfalls wertvolle Informationen zum Clientobjektmodell: