Criando arquivos Office com OpenXML SDK

Introdução

Uma maneira muito comum de introduzir flexibilidade para nossas aplicações é exportar os dados para arquivos Office: ao exportar para o Word, podemos gerar relatórios poderosos, onde o usuário pode formatar os dados da maneira desejada, editar ou remover partes dos dados, ou mesmo complementar com dados de diversas fontes. Exportando para o Excel, podemos criar rapidamente análises diversas, elaborar gráficos ou fazer comparações facilmente.

Uma maneira de exportar os dados para arquivos Office é usar a automação Office, que usa os recursos de automação COM para abrir o programa e gerar os arquivos a partir de nossos dados. Isso, além de muito lento, traz uma segunda desvantagem: obriga que a máquina que está rodando a aplicação tenha o Office instalado.

A partir do Office 2007, o formato de arquivos Office mudou, para um formato aberto, o OpenXML (http://openxmldeveloper.org/). Isto trouxe algumas vantagens:

  • Documenta o formato de arquivos Office – antes do OpenXML, o formato de arquivos Office não era documentado, e para criar manualmente estes arquivos, você tinha que usar muita engenharia reversa e mudar o programa a cada nova versão do Office;
  • Cria a possibilidade de intercâmbio entre programas – qualquer um pode criar um processador de textos que usa o formato OpenXML sem se preocupar com licenciamento;
  • Permite que você possa criar um programa para gerar ou alterar arquivos Office facilmente.

Um arquivo OpenXML é um arquivo compactado (no formato ZIP), que contém arquivos XML e outros arquivos de dados. Você pode usar qualquer tecnologia que abra arquivos ZIP e acesse arquivos XML para criar ou modificar os novos arquivos Office.

Se você renomear um arquivo Office para .zip e abri-lo, terá algo semelhante a isso:

OpenXML: conteúdo

Você tem um arquivo ZIP com três pastas e um arquivo XML. No diretório _rels você tem um arquivo .rels, um XML com a estrutura do documento. A partir daí, você vai “desenrolando” seu documento e obtendo as diversas partes que o compõem: propriedades, textos, imagens, estilos, etc. Parece complicado? Mas nós nem começamos ainda!

Packaging API

Para facilitar a manipulação de arquivos OpenXML, a Microsoft introduziu no .Net 3.0 a Packaging API, uma API para acessar arquivos que tem este formato de pacotes. Esta não é uma API específica para arquivos Office, você pode, por exemplo, abrir um arquivo XPS com a mesma API ou então criar um arquivo que use uma estrutura semelhante, mas que não seja compatível com OpenXML.

Para exemplificar esta API, vamos criar um programa WPF que abre um arquivo Office e mostra as suas relações. No Visual Studio, crie um novo projeto WPF e, na janela principal, coloque o seguinte código:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <ListBox x:Name="LbxDados" />
    <Button Content="Abre" HorizontalAlignment="Center" Grid.Row="1"
        VerticalAlignment="Center" Width="75" Height="25"
        Click="AbreArquivoClick"/>
</Grid>

No Code Behind, no manipulador do evento Click do botão, coloque o seguinte código:

private void AbreArquivoClick(object sender, RoutedEventArgs e)
{
    var openDialog = new OpenFileDialog
                     {
                         Filter =
                             "Arquivos Office (*.docx,*.xmlx,*.pptx)| "+
                             "*.docx;*.xlsx;*.pptx|Todos Arquivos (*.*)|*.*",
                     };
    if (openDialog.ShowDialog() == true)
    {
        using (Package package = Package.Open(openDialog.FileName, 
                   FileMode.Open, FileAccess.Read))
        {
            LbxDados.ItemsSource = package.GetRelationships();
        }
    }
}

Com isso, iremos pegar as relações do documento aberto e colocá-las na ListBox. Quando você executa o programa, irá ver algo semelhante ao seguinte:

OpenXML: execução

Isto é devido ao fato que a Packaging API abriu o arquivo .rels, fez a análise do arquivo XML e criou classes do tipo PackageRelationship. Para apresentar seus valores, basta colocar um ItemTemplate para a ListBox:

<ListBox x:Name="LbxDados">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Id}"/>
                <TextBlock Text="{Binding RelationshipType}"/>
                <TextBlock Text="{Binding TargetUri}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Agora os dados são apresentados como queremos:

OpenXML: execução

Podemos ver aqui dois arquivos de propriedades, docProps/app.xml (extended properties) e docProps/core.xml (core properties) e que o documento aberto é uma planiha Excel, que está no diretório xl e tem o nome workbook.xml. Poderíamos, em seguida, abrir o arquivo workbook.xml e analisá-lo, mas isso não é um trabalho simples. Teríamos que analisar as dependências do documento, ver quais as partes que compõem ele para montar toda sua estrutura.

Pensando nessa dificuldade, a Microsoft lançou a OpenXML SDK, um kit de desenvolvimento próprio para os arquivos OpenXML.