Compartilhar via


Este artigo foi traduzido por máquina.

SharePoint e Open XML

Gerar documentos do SharePoint com controles de conteúdo XML aberto

Eric White

Baixar o código de exemplo

Geralmente é o caso que um gerente de departamento precisa para enviar um relatório de status bem formatado regularmente para gerente geral ou que um líder de equipe precisa para enviar um relatório semanal de status para um número de partes interessadas. Para colaborar com outras pessoas em suas organizações, o gerente e o líder de equipe podem manter as informações de status nas listas do SharePoint. A questão para desenvolvedores é a incluir as informações nas listas de um documento como um relatório de status.

XML aberto, o formato de arquivo padrão para Office 2007, é um padrão ISO (documentado em detalhes no IS29500 exacting). Simplesmente, colocar XML aberto arquivos são arquivos ZIP que contêm XML e é muito fácil gerar ou modificar documentos XML abertos por meio de programação. Tudo o que você precisa é uma biblioteca para abrir um arquivo zip e uma API de XML. Usando os recursos à programação do Open XML e do SharePoint, você pode colocar juntos um sistema de geração de documento pequeno que aproveita os controles de conteúdo XML abertos e coloca pessoas como o gerente e líder de equipe encarregada de seus relatórios. Neste artigo, apresentarei alguns orientação e o código de exemplo para criar um sistema de geração de documento que usa listas do SharePoint para preencher tabelas em um documento de processamento de texto XML aberto.

Visão geral sobre o exemplo

O exemplo neste artigo é uma pequena Web Part do SharePoint que gera um documento de processamento de texto XML aberto a partir de dados que reside em listas do SharePoint. Criei dois SharePoint listas personalizadas, mostradas na de Figura 1, que contêm os dados que deseja inserir nas tabelas.


A Figura 1 SharePoint personalizado duas listas

Também criei um documento de processamento de texto Abrir XML de modelo que contém controles de conteúdo definindo a listas e colunas que são a origem dos dados de documento gerado. Os controles são mostrados na do Figura 2.


Figura 2 O documento XML modelo abrir com controles de conteúdo

Finalmente, criei uma Web Part que recupera a lista de documentos do modelo de uma biblioteca de documentos específicas e apresenta a lista de usuários. Um usuário seleciona um item na lista e, em seguida, clica no botão gerar relatório. A Web Part cria um documento de processamento de texto XML aberto, coloca-o na biblioteca de documentos relatórios e redireciona o usuário para essa biblioteca para que ela possa abrir o relatório. A Web Part é mostrada na do Figura 3 e o documento que ele gera é mostrado no do Figura 4.


Figura 3 uma Web Part que permite que usuários selecionem um modelo de documento

Controles de conteúdo XML aberto

Antes de descrever a solução do SharePoint, abordarei as noções básicas sobre controles de conteúdo XML aberto. Os controles de conteúdo abertos XML fornecem um recurso em documentos de processamento de texto que permite que você delinear conteúdo e associar metadados esse conteúdo. Para usar controles de conteúdo, você deve ativar a guia Desenvolvedor na Microsoft Office Word 2007. (Clique em Opções de Word no menu Office;em seguida, na caixa de diálogo Opções do Word, selecione Mostrar guia Desenvolvedor na faixa de opções.)

Para inserir um controle de conteúdo, selecione um texto e, em seguida, clique no botão na área de controles da guia desenvolvedor que cria um controle de conteúdo do texto sem formatação, mostrado na do Figura 5.


Figura 4 um XML aberto Word-Processing documento que contém o relatório gerado


Figura 5 usar este botão para criar um controle de conteúdo de texto sem formatação

Você pode definir propriedades para um controle de conteúdo dar um título e atribuir a ele uma marca. Clique no controle de conteúdo e, em seguida, clique no botão Propriedades na área de controles na guia desenvolvedor. Isso exibe uma caixa de diálogo que você pode usar para definir o título e a marca.

Controles de conteúdo utiliza o elemento w:sdt na marcação XML abertos, que é mostrada na de Figura 6. O conteúdo do controle de conteúdo é definido no elemento w:sdtContent. Na figura, você também pode ver o título do controle de conteúdo no elemento w:alias e a marca de controle de conteúdo no elemento w:tag.

Programação para XML aberto usando o .NET Framework

Você pode tomar uma variedade de abordagens para a programação para XML aberto usando o Microsoft .NET Framework:

  • Usar as classes no System.IO.Packaging
  • Use o SDK para XML aberto com qualquer um dos XML programação tecnologias disponíveis no. NET, incluindo XmlDocument, XmlParser ou LINQ para XML. Meu favorito é LINQ para XML.
  • Use o modelo de objeto com rigidez de tipos do SDK do Open XML versão 2.0. Você pode encontrar um número de artigos que apresentam como programar com este modelo de objeto.

Aqui, vou usar o SDK para XML aberto (qualquer versão 1.0 ou 2.0) com o LINQ para XML. Você pode baixar o SDK para XML aberto do de go.microsoft.com/fwlink/?LinkId=127912.

É útil encapsular a funcionalidade XML abertos em torno de controles de conteúdo em uma classe ContentControlManager. Quando você aborda o problema dessa maneira, você pode desenvolver sua funcionalidade XML abrir em um aplicativo de console simples. Depois de ter codificado e depurado sua funcionalidade XML aberto, você pode incorporá-lo em seu recurso do SharePoint com um mínimo de esforço. É bastante demorado incorrer a sobrecarga de implantar o recurso do SharePoint durante a depuração código XML aberto.

Nosso exemplo de geração de documentos do SharePoint, queremos escrever algum código que recupera um modelo de documento de uma biblioteca de documentos específicos, o documento para o conteúdo controles que ele contém consultas e usa os metadados armazenados em cada conteúdo de controle para preencher o documento com dados de lista do SharePoint apropriado.

Se você baixar o exemplo e examinar o documento XML aberto modelo, você verá que ele contém um controle de conteúdo ao redor de cada tabela e que controles de conteúdo são inseridos em cada célula na linha inferior de cada tabela. A marca para cada controle de conteúdo nas células da tabela especifica o nome de uma coluna nas listas do SharePoint. Para sua conveniência, também defini o título de cada controle de conteúdo para o mesmo valor como a marca. Controles de conteúdo exibem seu título quando o ponto de inserção estiver dentro do controle.

Quando você escreve o código para um recurso do SharePoint que gera um documento XML aberto, o código deve primeiro consultar o documento para esses controles de conteúdo. A consulta retorna uma árvore XML que descreve a estrutura de controles de conteúdo, juntamente com a marca para cada um. Se você executar esse código no documento de exemplo, ela produz o seguinte XML:

<ContentControls>

  <Table Name="Team Members">

    <Field Name="TeamMemberName" />

    <Field Name="Role" />

  </Table>

  <Table Name="Item List">

    <Field Name="ItemName" />

    <Field Name="Description" />

    <Field Name="EstimatedHours" />

    <Field Name="AssignedTo" />

  </Table>

</ContentControls>

Este mostra do documento XML que listas do SharePoint nosso código precisa consultar. Para cada item na lista, você precisará recuperar os valores de colunas especificados. O código para consultar o documento de processamento de texto XML aberto, mostrado na de Figura 7, é escrito como um LINQ para XML consulta que usa a construção funcional para formar o XML retornado.

Para usar construção funcional, o código instancia um objeto XElement usando seu construtor, passando um LINQ para XML consulta como um argumento para o construtor. A consulta LINQ para XML usa métodos de eixo para recuperar os elementos apropriados no corpo do documento e usa o método de extensão Enumerable.Select para formar novo XML dos resultados da consulta. Construção funcional exige um pouco de estudo para compreender, mas como você pode ver, depois de quebrar a cabeça ao redor dele, você pode fazer um muitos com apenas um pouco de código.

Figura 6 Abrir XML marcação para um controle de conteúdo

<w:p>

<w:r>

<w:t xml:space="preserve">Not in content control. </w:t>

</w:r>

<w:sdt>

<w:sdtPr>

<w:alias w:val="Test"/>

<w:tag w:val="Test"/>

<w:id w:val="5118254"/>

<w:placeholder>

<w:docPart w:val="DefaultPlaceholder_22675703"/>

</w:placeholder>

</w:sdtPr>

<w:sdtContent>

<w:r>

<w:t>This is text in content control.</w:t>

</w:r>

</w:sdtContent>

</w:sdt>

<w:r>

<w:t xml:space="preserve"> Not in content control.</w:t>

</w:r>

</w:p>

Preatomization de objetos XNamespace e XName

O código no do Figura 7 usa uma abordagem chamada "preatomization"do LINQ para XML nomes. Essa é apenas uma maneira sofisticada de dizer que você escrever uma classe estática (consulte do Figura 8) que contém campos estáticos que são inicializados para os qualificado nomes dos elementos e atributos que você está usando.

Figura 7 Recuperando a estrutura dos controles de conteúdo no documento de modelo

public static XElement GetContentControls(

WordprocessingDocument document)

{

XElement contentControls = new XElement("ContentControls",

document

.MainDocumentPart

.GetXDocument()

.Root

.Element(W.body)

.Elements(W.sdt)

.Select(tableContentControl =>

new XElement("Table",

new XAttribute("Name", (string)tableContentControl

.Element(W.sdtPr).Element(W.tag).Attribute(

W.val)),

tableContentControl

.Descendants(W.sdt)

.Select(fieldContentControl =>

new XElement("Field",

new XAttribute("Name",

(string)fieldContentControl

.Element(W.sdtPr)

.Element(W.tag)

.Attribute(W.val)

)

)

)

)

)

);

return contentControls;

}

Há um bom motivo para inicializar XName e XNamespace objetos dessa maneira. LINQ para XML abstrai nomes XML e espaços para nome em duas classes: System.Xml.Linq.XName e System.Xml.Linq.XNamespace, respectivamente. A semântica dessas classes incluem a noção de que, se dois XNames têm o mesmo nome qualificado (namespace + nome local), eles ser representados pelo mesmo objeto. Isso possibilita a comparação rápida dos objetos XName. Em vez de usar uma comparação de seqüência de caracteres para selecionar objetos XElement de um determinado nome, o código precisa somente comparar objetos. Quando você inicializa um objeto XName, LINQ para XML primeiro procura em um cache para determinar se um objeto XName com o mesmo namespace e nome já existe. Se houver, o objeto é inicializado para o objeto XName existente do cache. Se não existir, LINQ para XML inicializa um novo nome e o adiciona para o cache. Como você pode imaginar, se esse processo é repetido várias vezes, isso pode resultar em problemas de desempenho. Inicializando esses objetos em uma classe estática, o trabalho é feito apenas uma vez. Além disso, usando essa técnica você reduzir a possibilidade de um nome de elemento ou atributo é escrito incorretamente no corpo do código. Uma outra vantagem é que usando essa técnica, você obtém suporte do IntelliSense, que torna a escrever programas Open XML usando o LINQ para XML mais fácil.

Figura 8 A classe estática contendo campos estáticos para Preatomize objetos XNamespace e XName

public static class W

{

public static XNamespace w =

"https://schemas.openxmlformats.org/wordprocessingml/2006/main";

public static XName body = w + "body";

public static XName sdt = w + "sdt";

public static XName sdtPr = w + "sdtPr";

public static XName tag = w + "tag";

public static XName val = w + "val";

public static XName sdtContent = w + "sdtContent";

public static XName tbl = w + "tbl";

public static XName tr = w + "tr";

public static XName tc = w + "tc";

public static XName p = w + "p";

public static XName r = w + "r";

public static XName t = w + "t";

public static XName rPr = w + "rPr";

public static XName highlight = w + "highlight";

public static XName pPr = w + "pPr";

public static XName color = w + "color";

public static XName sz = w + "sz";

public static XName szCs = w + "szCs";

}

GetXDocument os métodos de extensão PutXDocument

O exemplo apresentado neste artigo também usa outro truque para facilitar a programação e melhorar o desempenho. O SDK para XML aberto tem a capacidade para colocar anotações em partes do documento. Isso significa que você pode anexar qualquer objeto do .NET Framework para um objeto OpenXmlPart e recuperá-lo mais tarde especificando o tipo do objeto que você anexou.

Podemos definir dois extensão métodos, GetXDocument e PutXDocument, que usar anotações para minimizar a desserialização de XML da parte XML aberto. Quando chamamos GetXDocument, primeiro parece para ver se uma anotação do tipo que XDocument existe no OpenXmlPart. Se a anotação existir, GetXDocument retorna. Se a anotação não existir, o método preenche um XDocument da parte, anota a parte e, em seguida, retorna o novo XDocument.

O método de extensão PutXDocument também verifica se há uma anotação do tipo XDocument. Se existir esta anotação, PutXDocument grava XDocument (supostamente modificada depois que o código chama GetXDocument) para o OpenXMLPart. Os métodos de extensão GetXDocument e PutXDocument são mostrados no do Figura 9. Você pode ver o uso do método de extensão GetXDocument no método GetContentControls listado anteriormente do Figura 7.

Métodos de extensão de Figura 9 usar anotações de SDK para XML aberto para minimizar a desserialização de XML

public static class AssembleDocumentLocalExtensions

{

public static XDocument GetXDocument(this OpenXmlPart part)

{

XDocument xdoc = part.Annotation<XDocument>();

if (xdoc != null)

return xdoc;

using (Stream str = part.GetStream())

using (StreamReader streamReader = new StreamReader(str))

using (XmlReader xr = XmlReader.Create(streamReader))

xdoc = XDocument.Load(xr);

part.AddAnnotation(xdoc);

return xdoc;

}

public static void PutXDocument(this OpenXmlPart part)

{

XDocument xdoc = part.GetXDocument();

if (xdoc != null)

{

// Serialize the XDocument object back to the package.

using (XmlWriter xw =

XmlWriter.Create(part.GetStream

(FileMode.Create, FileAccess.Write)))

{

xdoc.Save(xw);

}

}

}

}

Substituindo os controles de conteúdo de dados

Agora que temos um método que retorna a estrutura dos controles de conteúdo nas tabelas e células, precisamos de um método (SetContentControls) que cria um documento XML aberto com dados específicos (recuperados das listas do SharePoint) inseridos nas tabelas. Podemos definir este método para assumir uma árvore XML como um argumento. A árvore XML é mostrada na Figura 10 e do Figura 11 mostra o documento SetContentControls cria quando ele é passado a árvore XML.

Figura 10 uma árvore XML que contém dados para inserir no documento tabelas Word-Processing

<ContentControls>

<Table Name="Team Members">

<Field Name="TeamMemberName" />

<Field Name="Role" />

<Row>

<Field Name="TeamMemberName" Value="Bob" />

<Field Name="Role" Value="Developer" />

</Row>

<Row>

<Field Name="TeamMemberName" Value="Susan" />

<Field Name="Role" Value="Program Manager" />

</Row>

<Row>

<Field Name="TeamMemberName" Value="Jack" />

<Field Name="Role" Value="Test" />

</Row>

</Table>

<Table Name="Item List">

<Field Name="ItemName" />

<Field Name="Description" />

<Field Name="EstimatedHours" />

<Field Name="AssignedTo" />

<Row>

<Field Name="ItemName" Value="Learn SharePoint 2010" />

<Field Name="Description" Value="This should be fun!" />

<Field Name="EstimatedHours" Value="80" />

<Field Name="AssignedTo" Value=”All” />

</Row>

<Row>

<Field Name="ItemName" Value=

"Finalize Import Module Specification" />

<Field Name="Description" Value="Make sure to handle all document

formats." />

<Field Name="EstimatedHours" Value="35" />

<Field Name="AssignedTo" Value=”Susan" />

</Row>

<Row>

<Field Name="ItemName" Value="Write Test Plan" />

<Field Name=”Description" Value=

"Include regression testing items." />

<Field Name="EstimatedHours" Value="20" />

<Field Name="AssignedTo" Value="Jack" />

</Row>

</Table>

</ContentControls>


Figura 11 O documento gerado

Você pode ver que a única linha que contenha controles de conteúdo foi substituída por várias linhas, cada uma contendo os dados da árvore de XML que foi passado como um argumento para o método. Usando uma árvore XML para passar os dados para o código que manipula a marcação XML aberto, você obter uma boa separação do código que usa o modelo de objeto do SharePoint e o código XML aberto.

O código para montar o novo documento honra qualquer formatação aplicada à tabela. Por exemplo, se você configurou a tabela para Mostrar cores diferentes para linhas alternadas ou se você definir a cor de plano de fundo de uma coluna, o documento recém-gerado reflete as alterações de formatação.

Se você baixar e examinar o exemplo a ContentControlManager, você pode ver que o código obtém uma cópia da linha que contém controles de conteúdo e o salva como uma linha de protótipo:

// Determine the element for the row that contains the content controls.

// This is the prototype for the rows that the code will generate from data.

XElement prototypeRow = tableContentControl

    .Descendants(W.sdt)

    .Ancestors(W.tr)

    .FirstOrDefault();

Em seguida, para cada item recuperado da lista do SharePoint, o código clona a linha de protótipo, altera a linha clonada com os dados da lista do SharePoint e o adiciona a uma coleção que é inserida no documento.

Depois de criar a lista de novas linhas, o código remove a linha de protótipo da lista e insere a coleção de linhas recém-criadas, como mostrado aqui:

XElement tableElement = prototypeRow.Ancestors(W.tbl).First();

prototypeRow.Remove();

tableElement.Add(newRows);

Criando o recurso do SharePoint

Usei o CTP de fevereiro de 2009 versão das extensões de Visual Studio 2008 para o Windows SharePoint Services 3.0, v1.3 para criar este exemplo. Eu tenha criado e executar este exemplo em versões de 32 bits e 64 bits do WSS. (Kirk Evans tem alguns de webcasts excelente que mostram como usar essas extensões.)

O exemplo contém o código para criar os controles de Web Part. O código é bastante auto-explicativo se você está acostumado a criação de Web Parts do SharePoint. Quando um usuário clica no botão gerar relatório, as chamadas de código o método CreateReport, que monta o novo documento de processamento de texto Abrir XML do modelo de documento usando os dados no SharePoint lista conforme configurado nas marcas de controls.There conteúdo são alguns pontos a Observação sobre o código para o método CreateReport. Arquivos em uma biblioteca de documentos do SharePoint são retornados como matrizes de bytes. Você precisará converter essa matriz de bytes em um fluxo de memória para que você possa abrir e modificar o documento usando o SDK para XML abrir. Um dos construtores MemoryStream leva uma matriz de bytes e você pode ficar tentado a usar esse construtor. No entanto, o fluxo de memória criado com que o construtor é um fluxo de memória nonresizable, e o SDK para XML aberto requer que o fluxo de memória seja redimensionável. A solução é criar um MemoryStream com o construtor padrão e, em seguida, gravar a matriz de bytes do SharePoint em MemoryStream, conforme mostrado no Figura 12.

Figura 12 gravar uma matriz de bytes do SharePoint em um MemoryStream

private ModifyDocumentResults CreateReport(SPFile file, Label message)

{

byte[] byteArray = file.OpenBinary();

using (MemoryStream mem = new MemoryStream())

{

mem.Write(byteArray, 0, (int)byteArray.Length);

try

{

using (WordprocessingDocument wordDoc =

WordprocessingDocument.Open(mem, true))

{

// Get the content control structure from the template

// document.

XElement contentControlStructure =

ContentControlManager.GetContentControls(wordDoc);

// Retrive data from SharePoint,

constructing the XML tree to

// pass to the ContentControlManager.SetContentControls

// method.

...

}

}

}

}

O restante do código é simples. Ele usa o modelo de objeto do SharePoint para recuperar bibliotecas de documentos e o conteúdo das bibliotecas, recuperar listas e recuperar valores de colunas para cada linha na lista. Ele reúne a árvore XML para passar para ContentControlManager.SetContentControls e, em seguida, ele chama SetContentControls.

O código monta o nome do documento relatório gerado como dd relatório-aaaa-mm-. Se o relatório já existir, o código acrescentará um número ao nome do relatório para disambiguate o relatório de outros relatórios que já tiverem sido gerados. Por exemplo, se relatório-2009-08-01.docx já existir, o relatório será gravado para .docx relatório 2009 8-2 (1).

Personalizações fácil

Você provavelmente desejará personalizar este exemplo para atender às suas próprias necessidades. Um aperfeiçoamento possível é permitir que um controle de conteúdo no corpo do documento de modelo que recebe clichê conteúdo de um documento especificado armazenado no SharePoint. Você poderia escrever o código para que você pode colocar o nome do documento que contém o texto clichê como texto no controle de conteúdo.

Além disso, este exemplo rígido-códigos os nomes de bibliotecas de documentos relatórios e o TemplateReports. Você pode remover essa restrição especificando essas informações em uma lista do SharePoint. O código, em seguida, saberia sobre o nome desta lista de configuração. Os nomes de bibliotecas de documentos relatórios e o TemplateReports poderiam ser orientados por dados da sua lista de configuração.

SharePoint é uma tecnologia poderosa que facilita para as pessoas em organizações colaborar. Abrir XML é uma tecnologia emergente poderosa que está alterando a maneira que geramos documentos. Usar as duas tecnologias juntos permite que você criar aplicativos em que as pessoas podem usar documentos para colaborar de novas maneiras.

Eric White é redator na Microsoft especializado nos formatos de arquivo XML abertos do Office, Office e SharePoint. Antes de entrar no 2005 na Microsoft, ele trabalhou como um desenvolvedor de um número de anos e, em seguida, iniciado PowerVista Software, uma empresa que desenvolveu e vendido widget um grade de plataforma cruzada. Ele escreveu livros no controle personalizado e desenvolvimento de GDI+. Leia seu blog em de blogs.msdn.com/ericwhite.