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 sld
elementos , sldLayout
, sldMaster
e 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 MoveParagraphToPresentation
GetFirstSlide
. 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;
}