Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010 con Open XML SDK 2.0

Resumen: el modelo de objetos de cliente administrado de Microsoft SharePoint Foundation 2010 permite escribir aplicaciones basadas en Microsoft .NET Framework que pueden obtener acceso a contenido de SharePoint desde clientes sin instalar código en el servidor que ejecuta SharePoint Foundation 2010. Open XML SDK 2.0 para Microsoft Office permite escribir aplicaciones para crear, cambiar y consultar documentos Open XML, el formato de documento predeterminado de 2007 Microsoft Office system y Microsoft Office 2010. El uso de estas dos tecnologías juntas permite escribir aplicaciones del lado cliente que funcionan con documentos Open XML almacenados en bibliotecas de documentos.

Última modificación: viernes, 04 de noviembre de 2011

Hace referencia a: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

En este artículo
Información general
Recuperación de documentos de bibliotecas de documentos
Modificación de documentos en bibliotecas de documentos
Carga de documentos a bibliotecas de documentos
Creación de documentos en memoria y adición a bibliotecas de documentos
Procesamiento de todos los documentos de una biblioteca
Creación de documentos de procesamiento de texto con formato Office Open XML desde bibliotecas wiki
Conclusión
Recursos adicionales

Se aplica a:  SharePoint Foundation 2010 | Microsoft Office 2010 | 2007 Microsoft Office system

Proporcionado por:  Eric White, Microsoft Corporation

Contenido

  • Información general

  • Recuperación de documentos de bibliotecas de documentos

  • Modificación de documentos en bibliotecas de documentos

  • Carga de documentos a bibliotecas de documentos

  • Creación de documentos en memoria y adición a bibliotecas de documentos

  • Procesamiento de todos los documentos de una biblioteca

  • Creación de documentos de procesamiento de texto con formato Office Open XML desde bibliotecas wiki

  • Conclusión

  • Recursos adicionales

Información general

El modelo de objetos de cliente administrado de Microsoft SharePoint Foundation 2010 es un conjunto de bibliotecas administradas basado en Microsoft .NET Framework que permite escribir código para que los equipos cliente funcionen con muchos de los objetos comunes de los sitios de SharePoint. Los programas que se ejecutan en el cliente pueden agregar y quitar listas, agregar, actualizar y eliminar elementos de lista, cambiar documentos en bibliotecas de documentos, crear sitios, administrar permisos de elementos y agregar y quitar elementos web de una página.

El formato de archivo Office Open XML (el formato de documentos de Microsoft Office 2007 y de Office 2010) es un estándar ISO/IEC (IS29500) que describe los elementos internos de documentos de procesamiento de texto, hojas de cálculo y presentaciones. Los archivos con formato Office Open XML se almacenan según la especificación Open Packaging Conventions (Convenciones de empaquetado abierto) (Parte 2 de IS29500). Se trata básicamente de archivos ZIP que contienen elementos XML. Open XML SDK 2.0 para Microsoft Office es una biblioteca administrada basada en .NET Framework que facilita la escritura de programas para crear, cambiar o consultar documentos Open XML. Al final de este artículo se incluye una lista de algunos recursos que le ayudarán a comenzar a trabajar con Open XML SDK 2.0.

El uso de estas dos tecnologías juntas permite algunos escenarios interesantes:

  • Se puede escribir una aplicación del lado cliente para crear documentos de procesamiento de texto o presentaciones a partir del contenido recuperado en otra parte y cargarlos automáticamente a una biblioteca de documentos en un sitio de SharePoint.

  • Se puede escribir una aplicación para consultar todos los documentos de una biblioteca de documentos y extraer información de cada documento.

  • Se puede escribir una aplicación para procesar todos los documentos de una biblioteca de documentos y hacer las mismas modificaciones en cada uno. Una posibilidad interesante es que se pueden quitar todos los comentarios e información personal y aceptar todos los cambios realizados en cada documento de la biblioteca de documentos.

  • Se puede extraer el contenido de un sitio wiki y crear un documento Open XML a partir de dicho contenido.

Este artículo se basa en la información presentada en Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010. Para obtener más información sobre cómo funciona el modelo de objetos de cliente administrado de SharePoint Foundation 2010, vea dicho artículo.

Recuperación de documentos de bibliotecas de documentos

Hay dos operaciones básicas cuando se trabaja con el modelo de objetos de cliente administrado de SharePoint Foundation 2010 y formatos Office Open XML: recuperar documentos y guardar documentos. En el ejemplo siguiente se recupera un documento de una biblioteca de documentos y se imprime el texto del primer párrafo.

Nota

En este artículo se usan aplicaciones de consola de Microsoft Windows para el código de muestra. No obstante, se puede usar el mismo método con otros tipos de aplicación.

Para crear el ejemplo, debe agregar referencias a los cuatro ensamblados. Se requieren dos ensamblados para obtener acceso al modelo de objetos de cliente administrado de SharePoint Foundation 2010: Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll.Se requieren dos ensamblados para usar Open XML SDK 2.0: DocumentFormat.OpenXml.dll y WindowsBase.dll.Para ver instrucciones detalladas acerca de cómo crear una aplicación de consola que use el modelo de objetos de cliente administrado de SharePoint Foundation 2010, vea Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010.

Para crear los ejemplos que se presentan en este artículo, también debe descargar e instalar Open XML SDK 2.0. Para ver instrucciones detalladas sobre cómo crear aplicaciones de Open XML SDK 2.0, vea Open XML SDK 2.0 para Microsoft Office. Para descargar Open XML SDK 2.0, vea el tema sobre Open XML SDK 2.0.

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.");
    }
}

En este ejemplo se obtiene un resultado similar al siguiente.

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

En este ejemplo se imprimen los campos que suelen usarse cuando se trabaja con documentos en bibliotecas de documentos:

  • El campo FileLeafRef contiene el nombre del archivo.

  • El campo FileDirRef contiene el nombre de la biblioteca de documentos. Si el archivo está en una carpeta, el campo FileDirRef también contiene el nombre de la carpeta.

  • El campo FileRef contiene el nombre completo, incluido el nombre de la biblioteca de documentos, el nombre de las carpetas y el nombre del archivo.

La consulta CAML busca un elemento en la biblioteca de documentos en el que el campo FileLeafRef tenga un valor de Test.docx, y establece el elemento RowLimit del elemento View en uno.

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

Dado que el ejemplo establece el elemento RowLimit en uno, la consulta devuelve un objeto ListItemCollection que contiene cero elementos o un elemento. En consecuencia, puede probar la aplicación usando listItems.Count == 1 para determinar si la consulta encuentra el documento.

Para recuperar el archivo, se usa el método OpenBinaryDirect() para devolver un objeto del tipo FileInformation.

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

El objeto FileInformation contiene una referencia a un flujo que se puede usar para secuenciar el archivo a nuestra aplicación. No obstante, esa secuencia no es una secuencia que se pueda cambiar de tamaño. El método Open() de la clase WordprocessingDocument toma una secuencia como un argumento. No obstante, dicha secuencia debe ser una secuencia que se pueda cambiar de tamaño. En consecuencia, debe crear un objeto MemoryStream y, a continuación, copiar de la secuencia devuelta por la propiedad Stream en el objeto MemoryStream. Si intentamos abrir el objeto WordprocessingDocument desde la secuencia devuelta por la propiedad Stream, el método Open() arroja una excepción, System.IO.IOException, con el mensaje "No se puede abrir porque el valor FileMode o FileAccess no es válido para la secuencia".

Es posible que observe que no era necesario llamar al método ExecuteQuery() antes de obtener acceso a la propiedad Stream. Esto se debe a que el método OpenBinaryDirect() no participa en la comunicación de red XML/JSON normal del modelo de objetos de cliente. El artículo Using the SharePoint Foundation 2010 Managed Client Object Model explica cómo el elemento cliente del modelo de objetos de cliente agrupa las solicitudes como XML, cómo se envía el XML al servidor, que procesa las solicitudes y cómo, a continuación, se envía la respuesta en JSON. Si carga archivos usando XML y JSON, el modelo de objetos de cliente convierte el documento con formato Office Open XML binario a codificación Base 64. No obstante, el uso de esta codificación es menos eficiente que enviar directamente los datos binarios. Recomendamos enviar datos binarios directamente, siempre que sea posible, ya que mejora la eficiencia de la aplicación y reduce el tráfico en la red.

Después de obtener un objeto MemoryStream, que puede cambiarse de tamaño si se creó usando el constructor que no toma parámetros, abra el documento usando el método Open() y procéselo de la forma habitual.

Nota de precauciónPrecaución

La clase MemoryStream contiene un constructor que toma una matriz de bytes, que después se usa como memoria auxiliar de la secuencia. No obstante, el constructor devuelve una secuencia de memoria cuyo tamaño no se puede cambiar. En consecuencia, no es posible usar el constructor para crear una secuencia de memoria para usar con la API de Open XML.

Modificación de documentos en bibliotecas de documentos

Puede cambiar el ejemplo anterior de forma tal que modifique el documento y coloque el documento modificado de vuelta en una biblioteca de documentos.

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.");
    }
}

Observe que en este ejemplo se pasó como verdadero el método Open() para poder cambiar el documento. Después de abrir el documento usando el método Open(), puede modificarlo de la forma habitual.

Después de salir del ámbito creado por la instrucción que abre el documento llamando al método Open(), el objeto MemoryStream contiene el documento modificado. Antes de secuenciarlo de vuelta al servidor, busque hasta el comienzo de la secuencia. A continuación, llame al método SaveBinaryDirect(), que colocará el documento modificado en la biblioteca de documentos.

Carga de documentos a bibliotecas de documentos

La siguiente operación consiste en cargar documentos existentes a una biblioteca de documentos. Puede cargar un documento llamando al método SaveBinaryDirect(), pasando la dirección URL relativa al servidor y una secuencia. En el ejemplo siguiente se carga un nuevo documento a la carpeta Documentos compartidos de un sitio de SharePoint.

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);
    }
}

Creación de documentos en memoria y adición a bibliotecas de documentos

Hay dos formas comunes de crear documentos usando las API de formatos Office Open XML:

  • Use un documento existente como plantilla, ábralo, modifíquelo a su gusto y, a continuación, guárdelo donde desee.

  • Cree un documento. Con frecuencia, esto se hace con la ayuda de la herramienta DocumentReflector incluida en Open XML SDK 2.0 para Microsoft Office. Esta herramienta permite generar el código Microsoft Visual C# para crear cualquier documento con formato Office Open XML.

En cualquiera de los dos casos, puede crear el documento en un objeto MemoryStream. El ejemplo siguiente lee un documento en una matriz de bytes, crea una secuencia de memoria de tamaño ajustable usando el constructor MemoryStream que no toma argumentos, escribe la matriz de bytes en MemoryStream, modifica el documento en la memoria y, a continuación, carga el documento recién modificado a la biblioteca Documentos compartidos de un sitio de SharePoint.

Para ejecutar este ejemplo, cree un documento de procesamiento de texto llamado Template.docx, inicialícelo con cualquier contenido que desee (o sin contenido), y colóquelo en el directorio binario donde ejecuta el ejemplo. El ejemplo inserta un nuevo párrafo al comienzo del documento antes de cargarlo a la biblioteca de documentos.

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);
        }
    }
}

Procesamiento de todos los documentos de una biblioteca

Es posible que en ocasiones desee procesar una iteración en todos los documentos de una biblioteca de documentos, realizando la misma consulta o modificación en cada documento. La biblioteca de documentos puede contener carpetas que contienen documentos y posiblemente subcarpetas. En el ejemplo siguiente se muestra cómo usar el atributo Scope=’Recursive’ del elemento View para procesar todos los documentos de una biblioteca de documentos, incluidos los documentos que se encuentran en subcarpetas.

Nota de precauciónPrecaución

Si va a procesar todos los documentos en una biblioteca de documentos que contiene más de 2000 documentos, debe implementar un algoritmo de paginación. Para obtener más detalles, vea Using the SharePoint Foundation 2010 Managed Client Object Model. Si crea una aplicación interactiva para hacerlo, le conviene usar procesamiento asincrónico. Para obtener más información, vea Procesamiento asincrónico.

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();
        }
    }
}

Cuando procese todos los documentos con formato Office Open XML de una biblioteca de documentos o carpeta, es conveniente usar una consulta CAML para filtrar los documentos y obtener los del tipo deseado, en este caso "docx". El código resaltado en la consulta Lenguaje de marcado de la aplicación de colaboración (CAML) del ejemplo muestra cómo hacerlo.

El proyecto PowerTools for Open XML contiene una biblioteca para aceptar todas las revisiones realizadas en un documento de procesamiento de texto. Con una sencilla modificación en este ejemplo, se puede crear un programa que procese una iteración en todos los documentos de una biblioteca de documentos y acepte los cambios de cada uno de ellos. Para encontrar la clase RevisionAccepter, vea la sección de descargas de PowerTools for Open XML.

Creación de documentos de procesamiento de texto con formato Office Open XML desde bibliotecas wiki

El uso de la API de Open XML junto con el modelo de objetos de cliente fomenta la aparición de soluciones innovadoras. Supongamos, por ejemplo, que un usuario de un sitio wiki desea distribuir un documento a personas que no tienen acceso a dicho sitio wiki. Esas personas pueden ser clientes o proveedores que no tienen acceso a la red corporativa, pero necesitan la información contenida en el sitio wiki. Puede convertir una biblioteca wiki de SharePoint en un documento de formato Office Open XML que se puede enviar a cualquier usuario que tenga Microsoft Office Word 2007 o Microsoft Word 2010. Esta sección muestra cómo hacerlo usando el modelo de objetos de cliente.

Use las capacidades altChunk del formato Office Open XML para hacerlo. WordprocessingML proporciona la capacidad necesaria para importar contenido externo a través del elemento altChunk. Para usar altChunk, siga este procedimiento:

  • Cree un elemento adicional en el paquete. El elemento puede tener varios tipos de contenido, incluidos documentos con formato Office Open XML completos, HTML o texto sin formato. En este ejemplo, se usa la capacidad para importar HTML.

  • Almacene el contenido que desee importar en el elemento.

  • Cuando se crea el elemento, se crea una relación desde el elemento del documento principal al nuevo elemento de formato alternativo.

  • Agregue un elemento w:altChunk a la ubicación en la que desee importar el contenido de formato alternativo. El atributo r:id del elemento w:altChunk identifica el contenido que se desea importar. El elemento w:altChunk es contenido a nivel de bloque, lo que significa que se puede insertar en el documento en cualquier parte donde pueda insertar un elemento de párrafo (w:p).

    En este ejemplo se extrae el HTML de cada tema en el wiki, se inserta cada página en su propio elemento y se importa cada elemento en el documento usando el elemento w:altChunk.

Nota importanteImportante

Un punto importante para tener en cuenta acerca de altChunk es que se usa sólo para importar contenido. Si abre el documento usando Word 2007 o Word 2010 y lo guarda, el documento guardado no contendrá la parte de contenido de formato alternativo ni el marcado altChunk que se refiere a él. Word 2007 o Word 2010 convierte el marcado de HTML a WordprocessingML, como elementos de párrafo (w:p), elementos de ejecución (w:r) y elementos de texto (w:t).

En el ejemplo siguiente se extrae el contenido de cada página wiki como HTML.

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("====================================");
        }
    }
}

A continuación, cambie la dirección URL que se pasa al constructor [M:Microsoft.SharePoint.Client.ClientContext.#Ctor] a la dirección URL del sitio de SharePoint. Cambie el título que se pasa al método GetByTitle() al título de una biblioteca wiki en el sitio de SharePoint.

En este ejemplo se usa LINQ to XML para dar formato (sangría) al XHTML recuperado de la biblioteca wiki. Cuando ejecute este ejemplo, verá algo como lo siguiente.

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>

Como puede ver, el contenido de cada página de la biblioteca wiki está incluido en un elemento <div>. Dentro del elemento <div> hay un elemento de tabla que el wiki usa para diseño. El elemento en el que está realmente interesado es el elemento <div> dentro de la celda de la tabla que tiene un atributo de clase con el valor ms-rte-layoutszone-outer.Cuando creamos el HTML para insertar en el elemento de importación de formato alternativo, dicho elemento <div> interno se inserta en el elemento <body> del documento HTML. A continuación, el ejemplo de código escribe el HTML recién creado en el elemento de contenido alternativo.

Nota de Visual BasicNota de Visual Basic

Esta conversión no convierte vínculos wiki a marcadores y vínculos dentro del documento. Además, hay ciertos caracteres que se pueden insertar en la página wiki que no se convierten correctamente. Es una prueba de concepto y está diseñada para mostrar las posibilidades de usar el modelo de objetos de cliente con la API del formato Office Open XML. No está diseñada para resolver todos los problemas asociados con la conversión de un wiki de SharePoint a un documento con formato Office Open XML.

En este ejemplo se extrae el contenido de todas las páginas de un wiki de SharePoint y se crea un documento de procesamiento de texto a partir de él.

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();
        }
    }
}

 

Proporciona mucha funcionalidad en menos de 130 líneas de código. Aquí se puede ver el aspecto de una de las páginas del wiki de SharePoint.

Figura 1. Página de una biblioteca wiki

Figura 1

 

La misma página, tal como se muestra en Word 2010, tiene este aspecto:

Figura 2. La misma página como un documento de procesamiento de texto con formato Office Open XML

Figura 2

 

Conclusión

El modelo de objetos de cliente de SharePoint Foundation 2010 permite escribir aplicaciones del lado cliente sumamente eficaces que funcionan con SharePoint Foundation 2010 y SharePoint Server 2010. Open XML SDK 2.0 permite crear, modificar y consultar documentos con formato Office Open XML. Cuando se usan juntos, permiten usar documentos Open XML de formas novedosas para colaborar y compartir información.

Recursos adicionales

En este artículo se combinan dos tecnologías: Open XML SDK 2.0 y el modelo de objetos de cliente administrado de SharePoint Foundation 2010. El lugar para empezar con Open XML es el centro para desarrolladores de Open XML en MSDN. Allí encontrará una gran cantidad de contenido, como artículos, vídeos de procedimientos y vínculos a numerosas entradas de blog. En particular, los siguientes vínculos proporcionan información importante para comenzar a usar XML SDK 2.0:

Hay muchos recursos que pueden ayudarle a comenzar a trabajar con el modelo de objetos de cliente administrado de SharePoint Foundation 2010. Primero, lea Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010. También se recomiendan los siguientes recursos para el modelo de objetos de cliente: