Compartilhar via


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

Este tópico mostra como utilizar as classes no SDK Open XML para o Office para mover um parágrafo de uma apresentação para outra através de programação.

Obter um Objeto PresentationDocument

No SDK Open XML, a PresentationDocument classe representa um pacote de documento de apresentação. Para trabalhar com um documento de apresentação, crie primeiro uma instância da PresentationDocument classe e, em seguida, trabalhe com essa instância. Para criar a instância de classe a partir do documento, chame o Open método que utiliza um caminho de ficheiro e um valor Booleano como segundo parâmetro para especificar se um documento é editável. Para abrir um documento para leitura/escrita, especifique o valor true para este parâmetro, conforme mostrado na instrução seguinte using . Neste código, o sourceFile parâmetro é uma cadeia que representa o caminho para o ficheiro a partir do qual pretende abrir o documento.

Com a v3.0.0+ o Close() método foi removido a favor de depender da instrução using. Isto garante que o Dispose() método é chamado automaticamente quando a chaveta de fecho é atingida. O bloco que segue a using instrução estabelece um âmbito para o objeto que é criado ou nomeado na using instrução , neste caso sourceDoc.

Estrutura básica do documento de apresentação

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

O main parte de um PresentationML pacote 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 diapositivos, a uma lista de master de diapositivos, a uma lista de notas master e a um folheto master lista. A lista de diapositivos refere-se a todos os diapositivos na apresentação; A lista de master de diapositivos refere-se a todos os modelos globais de diapositivos utilizados na apresentação; as notas master contêm informações sobre a formatação das páginas de notas; e o master de folheto descreve o aspeto de um folheto.

Um folheto é um conjunto impresso de diapositivos que podem ser fornecidos a uma audiência.

Além de texto e gráficos, cada diapositivo pode conter comentários e notas, pode ter um esquema e pode fazer parte de uma ou mais apresentações personalizadas. Um comentário é uma anotação destinada à pessoa que mantém o conjunto de diapositivos da apresentação. Uma nota é um lembrete ou texto destinado ao apresentador ou à audiência.

Outras funcionalidades que um PresentationML documento pode incluir: animação, áudio, vídeo e transições entre diapositivos.

Um PresentationML documento não é armazenado como um corpo grande numa única parte. Em vez disso, os elementos que implementam determinados agrupamentos de funcionalidades são armazenados em partes separadas. Por exemplo, todos os autores num documento são armazenados numa parte dos autores, enquanto cada diapositivo tem a sua própria parte.

ISO/IEC 29500: 2016

O seguinte exemplo de código XML representa uma apresentação que contém dois diapositivos indicados pelos 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>

Com o SDK Open XML, pode criar a estrutura e o conteúdo do documento com classes com tipos fortes que correspondem a elementos PresentationML. Pode encontrar estas classes no espaço de nomes. A tabela seguinte lista os nomes das classes que correspondem aos sldelementos , sldLayout, sldMastere notesMaster .

Elemento PresentationML Abrir Classe SDK XML Descrição
<sld/> Slide Diapositivo de Apresentação. É o elemento raiz de SlidePart.
<sldLayout/> SlideLayout Esquema de Diapositivo. É o elemento raiz de SlideLayoutPart.
<sldMaster/> SlideMaster Modelo Global de Diapositivos. É o elemento raiz de SlideMasterPart.
<notesMaster/> NotesMaster Modelo Global de Notas (ou handoutMaster). É o elemento raiz de NotesMasterPart.

Estrutura do Corpo do Texto da Forma

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

Este elemento especifica a existência de texto a ser contido na forma correspondente. Todo o texto visível e as propriedades relacionadas com texto visível estão contidas neste elemento. Podem existir múltiplos parágrafos e em parágrafos múltiplas execuções de texto.

© ISO/IEC 29500: 2016

A tabela seguinte lista os elementos subordinados do corpo do texto da 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 fragmento de Esquema XML seguinte 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 e MoveParagraphToPresentationGetFirstSlide. O primeiro método utiliza dois parâmetros de cadeia: um que representa o ficheiro de origem, que contém o parágrafo a mover e outro que representa o ficheiro de destino, para o qual o parágrafo é movido. O método abre ambos os ficheiros de apresentação e, em seguida, chama o GetFirstSlide método para obter o primeiro diapositivo em cada ficheiro. Em seguida, obtém a primeira TextBody forma em cada diapositivo e o primeiro parágrafo na forma de origem. Executa um deep clone do parágrafo de origem, copiando não só o próprio objeto de origem Paragraph , mas também tudo o que está contido nesse objeto, incluindo o respetivo texto. Em seguida, insere o parágrafo clonado no ficheiro de destino e remove o parágrafo de origem do ficheiro de origem, substituindo-o por um parágrafo de marcador de posição. Por fim, guarda os diapositivos 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.
static void MoveParagraphToPresentation(string sourceFile, string targetFile)
{
    // Open the source file as read/write.
    using (PresentationDocument sourceDoc = PresentationDocument.Open(sourceFile, true))
    // </Snippet1
    // 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(p1);

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

O GetFirstSlide método utiliza o PresentationDocument objeto transmitido, obtém a respetiva parte da apresentação e, em seguida, obtém o ID do primeiro diapositivo na lista de diapositivos. Em seguida, obtém o ID de relação do diapositivo, obtém a parte do diapositivo do ID da relação e devolve a parte do diapositivo ao método de chamada.

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

Código de exemplo

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

// 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))
    // </Snippet1
    // 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(p1);

        // Replace the removed paragraph with a placeholder.
        textBody1.AppendChild(new Drawing.Paragraph());
    }
}
// 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;
}

Confira também