Compartilhar via


Mover um parágrafo de uma apresentação para outra

Este tópico mostra como usar as classes no SDK Open XML para Office para mover um parágrafo de uma apresentação para outra programaticamente.

Obtendo um objeto PresentationDocument

No SDK do Open XML, a classe PresentationDocument representa um pacote de documento de apresentação. Para trabalhar com um documento de apresentação, primeiro crie uma instância da classe PresentationDocument e trabalhe com essa instância. Para criar a instância de classe a partir do documento, chame o método Open(String, Boolean) que usa um caminho de arquivo e um valor booliano como o segundo parâmetro para especificar se um documento é editável. Para abrir um documento para leitura/gravação, especifique o valor verdadeiro para esse parâmetro, conforme mostrado na instrução de uso a seguir. Neste código, o parâmetro de arquivo é uma cadeia de caracteres que representa o caminho para o arquivo do qual você deseja abrir o documento.

    using (PresentationDocument doc = PresentationDocument.Open(file, true))
    {
        // Insert other code here.
    }

A instrução using fornece uma alternativa recomendada para a sequência típica de .Open, .Save e .Close. Ela garante que o método Dispose (método interno usado pelo SDK do Open XML para limpar recursos) seja chamado automaticamente quando a chave de fechamento for atingida. O bloco que segue a instrução de uso estabelece um escopo para o objeto que é criado ou nomeado na instrução de uso , nesse caso , doc.

Estrutura básica do documento de apresentação

A estrutura básica do documento de um documento PresentationML consiste em várias partes, entre elas a main parte que contém a definição de apresentação. O texto a seguir da especificação ISO/IEC 29500 apresenta a forma geral de um pacote PresentationML .

A main parte de um pacote PresentationML começa com um elemento raiz de apresentação. Esse elemento contém uma apresentação que, por sua vez, se refere a uma lista de slides, uma lista de master de slides, uma lista de master de anotações e uma lista de master de apostila. A lista de slides refere-se a todos os slides na apresentação; A lista de master de slides refere-se a todos os mestres de slides usados na apresentação; as anotações master contém informações sobre a formatação de páginas de anotações; e a apostila master descreve como uma apostila parece.

Uma apostila é um conjunto impresso de slides que pode ser fornecido a uma audiência.

Além de texto e gráficos, cada slide pode conter comentários e anotações, pode ter um layout e pode fazer parte de uma ou mais apresentações personalizadas. Um comentário é uma anotação destinada à pessoa que mantém o deck de slides de apresentação. Uma nota é um lembrete ou um pedaço de texto destinado ao apresentador ou ao público-alvo.

Outros recursos que um documento PresentationML pode incluir o seguinte: animação, áudio, vídeo e transições entre slides.

Um documento PresentationML não é armazenado como um corpo grande em uma única parte. Em vez disso, os elementos que implementam determinados agrupamentos de funcionalidade são armazenados em partes separadas. Por exemplo, todos os comentários em um documento são armazenados em uma parte de comentário, enquanto cada slide tem sua própria parte.

© ISO/IEC29500: 2008.

O exemplo de código XML a seguir representa uma apresentação que contém dois slides denotados pelas IDs 267 e 256.

    <p:presentation xmlns:p="…" … > 
       <p:sldMasterIdLst>
          <p:sldMasterId
             xmlns:rel="https://…/relationships" rel:id="rId1"/>
       </p:sldMasterIdLst>
       <p:notesMasterIdLst>
          <p:notesMasterId
             xmlns:rel="https://…/relationships" rel:id="rId4"/>
       </p:notesMasterIdLst>
       <p:handoutMasterIdLst>
          <p:handoutMasterId
             xmlns:rel="https://…/relationships" rel:id="rId5"/>
       </p:handoutMasterIdLst>
       <p:sldIdLst>
          <p:sldId id="267"
             xmlns:rel="https://…/relationships" rel:id="rId2"/>
          <p:sldId id="256"
             xmlns:rel="https://…/relationships" rel:id="rId3"/>
       </p:sldIdLst>
           <p:sldSz cx="9144000" cy="6858000"/>
       <p:notesSz cx="6858000" cy="9144000"/>
    </p:presentation>

Usando o SDK do Open XML, você pode criar estrutura de documentos e conteúdo usando classes fortemente tipdas que correspondem a elementos PresentationML. Você pode encontrar essas classes no namespace DocumentFormat.OpenXml.Presentation . A tabela a seguir lista os nomes de classe das classes que correspondem aos elementos sld, sldLayout, sldMaster e notesMaster .

Elemento PresentationML Classe SDK Open XML Descrição
Sld Slide Slide de Apresentação. É o elemento raiz do SlidePart.
sldLayout SlideLayout Layout do Slide. É o elemento raiz do SlideLayoutPart.
sldMaster SlideMaster Mestre de Slides. É o elemento raiz do SlideMasterPart.
notesMaster NotesMaster Mestre de Anotações (ou handoutMaster). É o elemento raiz do NotesMasterPart.

Estrutura do Corpo do Texto de Forma

O texto a seguir da especificação ISO/IEC 29500 apresenta a estrutura desse elemento.

Esse elemento especifica a existência do texto a ser contido na forma correspondente. Todos os textos visíveis e propriedades relacionadas ao texto visível estão contidos nesse elemento. Pode haver vários parágrafos e em parágrafos várias execuções de texto.

© ISO/IEC29500: 2008.

A tabela a seguir lista os elementos filho do corpo do texto de forma e a descrição de cada um.

Elemento Filho Descrição
bodyPr Propriedades do corpo
lstStyle Estilos de lista de texto
p Parágrafos de texto

O seguinte fragmento de esquema XML define o conteúdo deste elemento:

    <complexType name="CT_TextBody">
       <sequence>
           <element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
           <element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/>
           <element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/>
       </sequence>
    </complexType>

Como funciona o código de exemplo

O código neste tópico consiste em dois métodos, MoveParagraphToPresentation e GetFirstSlide. O primeiro método usa dois parâmetros de cadeia de caracteres: um que representa o arquivo de origem, que contém o parágrafo a ser movido e um que representa o arquivo de destino, para o qual o parágrafo é movido. O método abre os dois arquivos de apresentação e chama o método GetFirstSlide para obter o primeiro slide em cada arquivo. Em seguida, ele obtém a primeira forma TextBody em cada slide e o primeiro parágrafo na forma de origem. Ele executa um clone profundo do parágrafo de origem, copiando não apenas o objeto parágrafo de origem em si, mas também tudo contido nesse objeto, incluindo seu texto. Em seguida, ele insere o parágrafo clonado no arquivo de destino e remove o parágrafo de origem do arquivo de origem, substituindo-o por um parágrafo espaço reservado. Por fim, ele salva os slides modificados em ambas as apresentações.

    // Moves a paragraph range in a TextBody shape in the source document
    // to another TextBody shape in the target document.
    public static void MoveParagraphToPresentation(string sourceFile, string targetFile)
    {
        // Open the source file as read/write.
        using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
        {
            // Open the target file as read/write.
            using (PresentationDocument targetDoc = PresentationDocument.Open(targetFile, true))
            {
                // Get the first slide in the source presentation.
                SlidePart slide1 = GetFirstSlide(sourceDoc);

                // Get the first TextBody shape in it.
                TextBody textBody1 = slide1.Slide.Descendants<TextBody>().First();

                // Get the first paragraph in the TextBody shape.
                // Note: "Drawing" is the alias of namespace DocumentFormat.OpenXml.Drawing
                Drawing.Paragraph p1 = textBody1.Elements<Drawing.Paragraph>().First();

                // Get the first slide in the target presentation.
                SlidePart slide2 = GetFirstSlide(targetDoc);

                // Get the first TextBody shape in it.
                TextBody textBody2 = slide2.Slide.Descendants<TextBody>().First();

                // Clone the source paragraph and insert the cloned. paragraph into the target TextBody shape.
                // Passing "true" creates a deep clone, which creates a copy of the 
                // Paragraph object and everything directly or indirectly referenced by that object.
                textBody2.Append(p1.CloneNode(true));

                // Remove the source paragraph from the source file.
                textBody1.RemoveChild<Drawing.Paragraph>(p1);

                // Replace the removed paragraph with a placeholder.
                textBody1.AppendChild<Drawing.Paragraph>(new Drawing.Paragraph());

                // Save the slide in the source file.
                slide1.Slide.Save();

                // Save the slide in the target file.
                slide2.Slide.Save();
            }
        }
    }

O método GetFirstSlide usa o objeto PresentationDocument passado, obtém sua parte de apresentação e obtém a ID do primeiro slide em sua lista de slides. Em seguida, ele obtém a ID de relação do slide, obtém a parte do slide da ID da relação e retorna a parte do slide para o método de chamada.

    // Get the slide part of the first slide in the presentation document.
    public static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
    {
        // Get relationship ID of the first slide
        PresentationPart part = presentationDocument.PresentationPart;
        SlideId slideId = part.Presentation.SlideIdList.GetFirstChild<SlideId>();
        string relId = slideId.RelationshipId;

        // Get the slide part by the relationship ID.
        SlidePart slidePart = (SlidePart)part.GetPartById(relId);

        return slidePart;
    }

Código de exemplo

Usando esse código de exemplo, você pode mover um parágrafo de uma apresentação para outra. Em seu programa, você pode usar a chamada a seguir para o método MoveParagraphToPresentation para mover o primeiro parágrafo do arquivo de apresentação "Myppt4.pptx" para o arquivo de apresentação "Myppt12.pptx".

    string sourceFile = @"C:\Users\Public\Documents\Myppt4.pptx";
    string targetFile = @"C:\Users\Public\Documents\Myppt12.pptx";
    MoveParagraphToPresentation(sourceFile, targetFile);

Depois de executar o programa, dê uma olhada no conteúdo dos arquivos de origem e de destino para ver o parágrafo movido.

Este é o código de exemplo completo em C# e em Visual Basic.


using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using System;
using System.Linq;
using Drawing = DocumentFormat.OpenXml.Drawing;

MoveParagraphToPresentation(args[0], args[1]);

// Moves a paragraph range in a TextBody shape in the source document
// to another TextBody shape in the target document.
static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
    // Open the source file as read/write.
    using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
    // Open the target file as read/write.
    using (PresentationDocument targetDoc = PresentationDocument.Open(targetFile, true))
    {
        // Get the first slide in the source presentation.
        SlidePart slide1 = GetFirstSlide(sourceDoc);

        // Get the first TextBody shape in it.
        TextBody textBody1 = slide1.Slide.Descendants<TextBody>().First();

        // Get the first paragraph in the TextBody shape.
        // Note: "Drawing" is the alias of namespace DocumentFormat.OpenXml.Drawing
        Drawing.Paragraph p1 = textBody1.Elements<Drawing.Paragraph>().First();

        // Get the first slide in the target presentation.
        SlidePart slide2 = GetFirstSlide(targetDoc);

        // Get the first TextBody shape in it.
        TextBody textBody2 = slide2.Slide.Descendants<TextBody>().First();

        // Clone the source paragraph and insert the cloned. paragraph into the target TextBody shape.
        // Passing "true" creates a deep clone, which creates a copy of the 
        // Paragraph object and everything directly or indirectly referenced by that object.
        textBody2.Append(p1.CloneNode(true));

        // Remove the source paragraph from the source file.
        textBody1.RemoveChild<Drawing.Paragraph>(p1);

        // Replace the removed paragraph with a placeholder.
        textBody1.AppendChild<Drawing.Paragraph>(new Drawing.Paragraph());

        // Save the slide in the source file.
        slide1.Slide.Save();

        // Save the slide in the target file.
        slide2.Slide.Save();
    }
}

// Get the slide part of the first slide in the presentation document.
static SlidePart GetFirstSlide(PresentationDocument presentationDocument)
{
    // Get relationship ID of the first slide
    PresentationPart part = presentationDocument.PresentationPart ?? presentationDocument.AddPresentationPart();
    SlideIdList slideIdList = part.Presentation.SlideIdList ?? part.Presentation.AppendChild(new SlideIdList());
    SlideId slideId = part.Presentation.SlideIdList?.GetFirstChild<SlideId>() ?? slideIdList.AppendChild<SlideId>(new SlideId());
    string? relId = slideId.RelationshipId;

    if (relId is null)
    {
        throw new ArgumentNullException(nameof(relId));
    }

    // Get the slide part by the relationship ID.
    SlidePart slidePart = (SlidePart)part.GetPartById(relId);

    return slidePart;
}