wordpress hit counter
Generate Open XML Presentations using a Presentation Template - OpenXML Developer - Blog - OpenXML Developer

Generate Open XML Presentations using a Presentation Template

Blog

Samples, Demos, and Reference Articles

Generate Open XML Presentations using a Presentation Template

  • Comments 4

One of the most effective ways to build document generation systems is to enable creation of a template document. Generated documents are a product of the template document and some data or code that replaces certain key portions of the template document with content that is specific to the generated document. WordprocessingML documents can contain content controls, which allow us to delineate the content to replace. However, PresentationML does not have content controls. This post presents an approach for building template presentations that you can use to generate custom presentations.

To understand the approach, watch the following screen-cast, which explains how to create a template presentation, and how to replace delineated content with custom content:

The gist of the approach is that instead of using content controls, you use a specific character sequence to delineate the content. In the example that I present here, I use the <# and #> sequences to delineate replacement content. The following sample slide shows what a template slide looks like.

The biggest problem around processing these special character sequences is that paragraphs are often broken into runs, and we can't control where PowerPoint 2010 will create the break between runs.  This means that if we are searching for the sequence "<# SomeKeyword #>", we almost certainly will need to search across runs.  In the following slide, you can see that the <# are in a run with the word "About".  The #> are in a run by themselves.  The keyword "AccountRep is in a run by itself.  The key point is that we don't know how these runs will be split up.

<a:p>
  <a:r>
    <a:rPr lang="en-US"
            dirty="0"
            smtClean="0"/>
    <a:t>About &lt;# </a:t>
  </a:r>
  <a:r>
    <a:rPr lang="en-US"
            dirty="0"
            err="1"
            smtClean="0"/>
    <a:t>AccountRep</a:t>
  </a:r>
  <a:r>
    <a:rPr lang="en-US"
            dirty="0"
            smtClean="0"/>
    <a:t> #&gt;</a:t>
  </a:r>
  <a:endParaRPr lang="en-US"
                dirty="0"/>
</a:p>

The solution is to break all runs up into multiple runs, each having a single character.  After breaking runs, the markup will look something like this (shortened for brevity):

<a:p>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      smtClean="0" />
    <a:t>r</a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      smtClean="0" />
    <a:t> </a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      smtClean="0" />
    <a:t>&lt;</a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      smtClean="0" />
    <a:t>#</a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      smtClean="0" />
    <a:t> </a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      err="1"
      smtClean="0" />
    <a:t>C</a:t>
  </a:r>
  <a:r>
    <a:rPr
      lang="en-US"
      dirty="0"
      err="1"
      smtClean="0" />
    <a:t>u</a:t>
  </a:r>
  <a:endParaRPr
    lang="en-US"
    dirty="0" />
</a:p>

After breaking into runs where each run has a single character, it is much easier to look for the pattern that starts with <# and ends with #>.  It then is straightforward to replace the sequence of runs that match the pattern with a new run with the generated content.  Then, after processing the slide, it is easy to coalesce adjacent runs.

The code for this example is attached to this blog post.

Attachment: ProcessPresentationTemplate.zip
  • Hey Eric, this is good. What I've done instead is just name textbox, search on that and then replace all runs within the paragraph with my run. The only issue I've found with that is when the run(s) to be replaced have custom formatting. I can usually move that formatting up to the paragraph properties, but not for all formatting. It requires more seperate text boxes though - each item to be replaced is it's own, so this it doesn't work for an inline replacement (i.e. if you had "Welcome <#Customer#>" and just wanted to replace "<#Customer#>".

  • Eric, This was really useful. I'm working on a project to "templatize"  presentations for senior members of a financial institution to allow rapid assembly and customization of  presentations to clients. This is just what I needed.

  • @tendoors, question: why can't you replace the content with a new run with the desired formatting?  Is it that you need to apply formatting that is only available for paragraphs?

    @jlobaugh, glad this was useful.

  • Hey everyone,

    I'm embarking on creating a template-based PPT generator and found this article helpful.  I need a bit more power and expressiveness than either of these approaches would deliver.  What I am planning on doing is to leverage the tag feature of PowerPoint (you can tag shapes, slides, and presentations). So rather than messing with the shapes text, I would put the template metadata into the shape's tag as XML.  A simple tag might be:

       <p><r>Literal text</r><p>

    To bind to an object, it would have

      <p><r>{myObj.someProperty}</r></p>

    Or if the shape has two runs, you could have the tag:

      <p><r>{myObj.someProperty}</r><r>{myObj.anotherProperty}</r></p>

    Even if the shape has a single paragraph and run, the template engine would follow the direction of the tag, so if the tag has

    <p>

     <r size="16" color="foreground">{myObj.someProperty}</r>

     <r>{myObj.anotherProperty}</r>

    </p>

    <p>

     <r size="16" color="foreground">{myObj2.someProperty}</r>

     <r size="16">{myObj2.anotherProperty}</r>

    </p>

    then the final shape will have two paras, each with two runs, and with the settings specified in the template.

    I'd be interested in all of your opinions on this approach.

Page 1 of 1 (4 items)