Partager via


Déplacer un paragraphe d’une présentation vers une autre

Cette rubrique montre comment utiliser les classes du Kit de développement logiciel (SDK) Open XML pour Office pour déplacer un paragraphe d’une présentation à une autre par programmation.

Obtention d’un objet PresentationDocument

Dans le Kit de développement logiciel (SDK) Open XML, la classe PresentationDocument représente un package de documents de présentation. Pour utiliser un document de présentation, créez d’abord une instance de la classe PresentationDocument, puis utilisez cette instance. Pour créer la classe instance à partir du document, appelez la méthode Open(String, Boolean) qui utilise un chemin d’accès de fichier et une valeur booléenne comme deuxième paramètre pour spécifier si un document est modifiable. Pour ouvrir un document en lecture-écriture, affectez la valeur true à ce paramètre, comme illustré dans l’instruction using suivante. Dans ce code, le paramètre file est une chaîne qui représente le chemin d’accès du fichier à partir duquel vous voulez ouvrir le document.

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

L'instruction using offre une alternative recommandée pour la séquence .Open, .Save, .Close standard. Elle garantit que la méthode Dispose (méthode interne utilisée par le kit de développement Open XML pour nettoyer les ressources) est automatiquement appelée lorsque l'accolade de fermeture est atteinte. Le bloc qui suit l’instruction using établit une étendue pour l’objet créé ou nommé dans l’instruction using, dans le cas présent doc.

Structure de document de présentation de base

La structure de document de base d’un document PresentationML est constituée d’un certain nombre de composants, parmi lesquels le composant principal qui contient la définition de la présentation. Le texte suivant de la spécification ISO/IEC 29500 présente la forme globale d’un package PresentationML .

La partie main d’un package PresentationML commence par un élément racine de présentation. Cet élément contient une présentation qui, à son tour, fait référence à une liste de diapositives, à une liste de diapositives master, à une liste de notes master et à un document master liste. La liste des diapositives référence toutes les diapositives de la présentation ; la liste de masques de diapositive référence tous les masques de diapositive utilisés dans la présentation ; le masque de pages de note contient des informations sur la mise en forme des pages de notes et le masque de document décrit comment un document se présente.

Un document à distribuer est un ensemble imprimé de diapositives qui peut être distribué aux personnes de l’audience.

En plus de textes et de graphiques, chaque diapositive peut contenir des commentaires et des notes, peut avoir une disposition et peut faire partie d’une ou plusieurs présentations personnalisées. Un commentaire est une annotation destinée à la personne qui gère le jeu de diapositives de la présentation. Une note est un rappel ou un élément de texte destiné au présentateur ou à l’audience.

Les autres fonctionnalités qu’un document PresentationML peut inclure les suivantes : animation, audio, vidéo et transitions entre les diapositives.

Un document PresentationML n’est pas stocké sous la forme d’un corps de grande taille dans un même composant. Au lieu de cela, les éléments qui implémentent certains groupes de fonctionnalités sont stockés dans des composants distincts. Par exemple, tous les commentaires d’un document sont stockés dans un même composant Commentaires, alors que chaque diapositive a son propre composant.

© ISO/IEC29500: 2008.

L’exemple de code XML suivant représente une présentation qui contient deux diapositives ayant les numéros d’identification 267 et 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>

À l’aide du Kit de développement logiciel (SDK) Open XML, vous pouvez créer une structure de document et du contenu à l’aide de classes fortement typées qui correspondent aux éléments PresentationML. Vous trouverez ces classes dans l’espace de noms DocumentFormat.OpenXml.Presentation . Le tableau suivant répertorie les noms des classes qui correspondent aux éléments sld, sldLayout, sldMaster et notesMaster.

Élément PresentationML Classe du Kit de développement logiciel (SDK) Open XML Description
Sld Slide Diapositive de présentation. Il s’agit de l’élément racine de SlidePart.
sldLayout SlideLayout Mise en page des diapositives. Il s’agit de l’élément racine de SlideLayoutPart.
sldMaster SlideMaster Masque des diapositives. Il s’agit de l’élément racine de SlideMasterPart.
Notesmaster NotesMaster Masque des pages de notes (ou handoutMaster). Il s’agit de l’élément racine de NotesMasterPart.

Structure du corps du texte d’une forme

Le texte suivant de la spécification ISO/IEC 29500 présente la structure de cet élément.

Cet élément spécifie l’existence du texte qui doit être contenu dans la forme correspondante. L’ensemble du texte visible et des propriétés relatives au texte visible est contenu dans cet élément. Il peut exister plusieurs paragraphes, dans lesquels il peut y avoir plusieurs séquences de texte.

© ISO/IEC29500: 2008.

Le tableau suivant répertorie les éléments enfants du corps du texte d’une forme, ainsi que la description correspondante.

Élément enfant Description
bodyPr Propriétés du corps
lstStyle Styles de liste du texte
p Paragraphes de texte

Le fragment de schéma XML suivant définit le contenu de cet élément :

    <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>

Fonctionnement de l’exemple de code

Le code de cette rubrique comprend deux méthodes, MoveParagraphToPresentation et GetFirstSlide. La première méthode accepte deux paramètres de chaîne : un paramètre qui représente le fichier source contenant le paragraphe à déplacer, et un autre paramètre qui représente le fichier cible de destination du paragraphe. La méthode ouvre les deux fichiers de présentation, puis appelle la méthode GetFirstSlide pour obtenir la première diapositive de chaque fichier. Elle obtient ensuite la première forme TextBody de chaque diapositive et le premier paragraphe de la forme source. Elle effectue un clonage approfondi du paragraphe source, en copiant non seulement l’objet Paragraph source lui-même, mais également tout ce qui est contenu dans cet objet, y compris son texte. Elle insère ensuite le paragraphe cloné dans le fichier cible et supprime le paragraphe source du fichier source, en le remplaçant par un paragraphe d’espace réservé. Enfin, elle enregistre les diapositives modifiées dans les deux présentations.

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

La méthode GetFirstSlide accepte l’objet PresentationDocument passé, obtient son composant Présentation, puis obtient l’ID de la première diapositive de sa liste de diapositives. Elle obtient ensuite l’ID de relation de la diapositive, obtient le composant Diapositive à partir de l’ID de relation, puis retourne le composant Diapositive à la méthode appelante.

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

Exemple de code

À l’aide de cet exemple de code, vous pouvez déplacer un paragraphe d’une présentation vers une autre présentation. Dans votre programme, vous pouvez utiliser l’appel suivant à la méthode MoveParagraphToPresentation pour déplacer le premier paragraphe du fichier de présentation « Myppt4.pptx » vers le fichier de présentation « Myppt12.pptx ».

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

Après avoir exécuté le programme, examinez le contenu du fichier source et du fichier cible pour constater le déplacement du paragraphe.

Voici l’exemple de code complet en C# et en 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;
}