Posts Tagged ‘Office Open XML’

Alternate OOXML Document Generation Approach

March 31, 2011

Eric White has put out a document generation example which uses XPath and Word Content Controls.  I applaud Eric for the amount of work he has done with his exploration of different ways to perform template base generation.  This is a subject that is challenging and we need as many ideas as we can get.  There are a couple of areas that I see room for improvement in this XPath design that I would like to bring up. 

The first is that Eric has chosen to put his document generation in the document itself.  I see this as a maintenance and reusability issue.  Architecturally I would prefer to have my code external to the document so that I can write and maintain it centrally in a generic fashion and tie it to a rules engine.

Another place I see that this approach falls down is that it is good for simple text replacement, but it doesn’t handle formatting, replacing images or working with charts.  This doesn’t mean that it can’t handle them, but I think it would lose the simplicity which looks to be it’s appeal.

Lastly, Content Controls are currently a Word only feature.  It would be great if we could come up with a mark-up technique that was universal to all Office document types.  Hey, we can dream, right?

Personally, I prefer a more meta data driven approach based on my experience with solutions which had output that was more marketing material quality.  That being said, but approach is an interesting idea to add to the design arsenal.  Thanks for the thoughts Eric.

Advertisements

Update Since Microsoft/PSC Office Open XML Case Study

December 16, 2010

In 2009 Microsoft released a case study about a project that we had done using the OOXML SDK 1.0 for Research Directors Inc.  Since that time Microsoft has released version 2.0 of the SDK and PSC has done significant development with it.  Below are some of the mile stones we have reached since the original case study.

At the time of the original case study two report types had been automated to output as PowerPoint presentations.  Now that the all the main products have been delivered we have added three reports with Word document outputs and five more reports with PowerPoint outputs.

One improvement we made over the original application was to create a PowerPoint Add-In which allows the users to tag a slide.  These tags along with the strongly typed SDK 2.0 allows for the code to use LINQ to easily search for slides in the template files.  This allows for a more flexible architecture base on assembling a presentation from copied slide extracted from the template.

The new library we created also enabled us to create two new Word based reports in two weeks.  The library we created abstracts the generation of the documents from the business logic and the data retrieval.  The key to this is the mark up.  Content Controls are a good method for identifying sections of a template to be modified or replaced.  Join this with the concept of all data being generically either scalar or two dimensional and the code becomes more generic.

In the end we found the OOXML SDK 2.0 to be a great tool for accelerating document generation development and creating happy clients. 

Creating New Presentations from Slide Masters Using OpenXML (Revisited)

May 4, 2010

Here’s an update to a prior post, Creating New Presentations from Slide Masters Using OpenXML, about creating new presentation slides from the slide master.  A reader commented about an error with layouts that had images in them and it came to my attention that my code completely ignored the images.  Here’s an update:

private static void InsertSlide(PresentationPart pPart, string layoutName, UInt32 slideId)

        {

            Slide slide = new Slide(new CommonSlideData(new ShapeTree()));

            SlidePart sPart = pPart.AddNewPart<SlidePart>();

            slide.Save(sPart);

            SlideMasterPart smPart = pPart.SlideMasterParts.First();

            SlideLayoutPart slPart = smPart.SlideLayoutParts.Single(kaark => kaark.SlideLayout.CommonSlideData.Name == layoutName);

            //Add the layout part to the new slide from the slide master

            sPart.AddPart<SlideLayoutPart>(slPart);

            sPart.Slide.CommonSlideData = (CommonSlideData)smPart.SlideLayoutParts.Single(kaark => kaark.SlideLayout.CommonSlideData.Name == layoutName).SlideLayout.CommonSlideData.Clone();

 

            using (Stream stream = slPart.GetStream())

            {

                sPart.SlideLayoutPart.FeedData(stream);

            }

 

            //UPDATED: Copy the images from the slide master layout to the new slide

            foreach (ImagePart iPart in slPart.ImageParts)

            {

                ImagePart newImagePart = sPart.AddImagePart(iPart.ContentType, slPart.GetIdOfPart(iPart));

                newImagePart.FeedData(iPart.GetStream());

            }

 

            SlideId newSlideId = pPart.Presentation.SlideIdList.AppendChild<SlideId>(new SlideId());

            newSlideId.Id = slideId;

            newSlideId.RelationshipId = pPart.GetIdOfPart(sPart);

        }

After feeding the slide layout part data into the new slide’s layout part, the code then adds the new image parts to the slide from the slide master layout.

Dealing With Table Borders In OOXML

April 5, 2010

Formatting tables in a document programmatically can be a very complex task.  This is the major reason which we start our document generation projects with templates instead of building components in a document by hand.

Borders are on aspect of a table that you may want to fomat.  Borders are used to make certain content in a table stand out.  If you need to conditionally set and remove borders there is something that you need to be aware of.  Even in OOXML you have the concepts of styles, inheriting styles and overriding styles.

When Word defines a table it will reference a global style such as “TableGrid”.  This style will include the borders for the table.  Specifically the InsideHorizontalBorder and InsideVerticalBorder define the borders for the cells.  These can be overridden by the TableCellBorders collection of a particular cell.  Adding a double right border on a cell is as easy as the couple of lines of code below.

wordprocessing.TableCellBorders borders = new wordprocessing.TableCellBorders();

borders.RightBorder = new RightBorder(){Val = BorderValues.Double, Color = "000000", ThemeColor = ThemeColorValues.Text1, Size = (UInt32Value)4U, Space = (UInt32Value)0U };

cell.TableCellProperties.Append(borders);

If I want to revert back to the table’s style for cell borders I simply need to remove all children from the TableCellBorders collection.  It is like removing a class identifier from a TD tag in HTML.  The style in the parent object takes back over.

With the knowledge of how the borders work you can take the concept and apply it to other effects of styles.

Creating New Presentations from Slide Masters Using OpenXML

March 24, 2010

The slide master in Powerpoint provides a powerful way for end-users to easily control the appearance and layouts of a presentation.  A slide master contains a set of layouts that are subsequently used by the slides in the presentation.

A common approach to constructing  a new presentation is to have a template with slides that are then copied/merged into the new presentation.  The approach I will be demonstrating creates slides in the new presentation based off the slide master layouts in the template.  This approach still requires a template, but does not require slides to already exist. 

The Template

The template I used contained a few layouts in the slide master, each arranged with some placeholder objects.  A great benefit of layouts in the slide master is that they can be renamed through the UI.  The layout name is what will be used in the code to construct the slide deck in the new presentation.

The Code

Now the fun part.  The InsertSlide method takes a PresentationPart, layout name from the slide master, and ID for the new slide.  It creates the new Slide and adds the associated parts to the PresentationPart, copying all the required layout and common slide data from the slide master layout.

   1: private static void InsertSlide(PresentationPart pPart, string layoutName, UInt32 slideId)

   2:         {

   3:             Slide slide = new Slide(new CommonSlideData(new ShapeTree()));

   4: 

   5:             SlidePart sPart = pPart.AddNewPart<SlidePart>();

   6:             slide.Save(sPart);

   7: 

   8:             SlideMasterPart smPart = pPart.SlideMasterParts.First();

   9:             SlideLayoutPart slPart = smPart.SlideLayoutParts.Single(kaark => kaark.SlideLayout.CommonSlideData.Name == layoutName);

  10:             sPart.AddPart<SlideLayoutPart>(slPart);

  11:             sPart.Slide.CommonSlideData = (CommonSlideData)smPart.SlideLayoutParts.Single(kaark => kaark.SlideLayout.CommonSlideData.Name == layoutName).SlideLayout.CommonSlideData.Clone();

  12:             using (Stream stream = slPart.GetStream())

  13:             {

  14:                 sPart.SlideLayoutPart.FeedData(stream);

  15:             }

  16: 

  17:             SlideId newSlideId = pPart.Presentation.SlideIdList.AppendChild<SlideId>(new SlideId());

  18:             newSlideId.Id = slideId;

  19:             newSlideId.RelationshipId = pPart.GetIdOfPart(sPart);

  20:         }

Since the presentation started with only a slide master in the template and no slides, a SlideIdList must be added to the PresentationPart.  Then start adding slides, using the layout names from the slide master.  Notice that the slide IDs were started at 256, that’s not a typo.  Slide IDs must be >= 256.

   1: using (PresentationDocument pDoc = PresentationDocument.Open(newFileCopiedFromTemplate, true))

   2:             {

   3:                 PresentationPart pPart = pDoc.PresentationPart;

   4: 

   5:                 pPart.Presentation.SlideIdList = new SlideIdList();

   6:                 InsertSlide(pPart, "Layout1", 256);

   7:                 InsertSlide(pPart, "Layout3", 257);

   8:                 InsertSlide(pPart, "Layout3", 258);

   9:                 InsertSlide(pPart, "Layout2", 259);

  10:                 pPart.Presentation.Save();

  11:                 pDoc.Close();

  12:             }

The Challenges of Inconsistent Implementation and Office Document Generation

January 29, 2010

I have spent the last several months developing solutions with Office 2007 and the Office Open XML SDK 2.  Our client has requirements that cross the suite from PowerPoint Presentations to Word Documents.  The Open XML standard which define the structure of these documents is very powerful.  My biggest frustration is the lack of consistent capabilities between the products. 

Since we are doing document generation based on templates it is very important we that the code can consistently identify any part of a document, whether that is a section of text, a chart, a table or an image.  While Word 2007 has Content Controls and Custom XML (2007 only) which can be used for marking up a document, similar features are not available in PowerPoint.  This is a major issue for us since the majority of our templated work is in PowerPoint.

A key to a successful solution for me is that a markup needs to be consistent in the way it is implemented in all of the Office applications.  It should also have a way that an end user can add a tag to a document without the risk of it being mislabeled because of human error.  This is one of the drawbacks of Content Controls.  Another thing that makes CustomXml more attractive is that you can use just one type of control to encapsulate content (more on Content Controls versus CustomXml in the next few days).  There are a variety of content controls that are tightly typed.  In other situations this may be a plus, but if anything the developer should be able to define the type of objects used for tagging.

Further, the fact that something as simple as a Text object being in a different namespace even within the same document type means that we have to write duplicate code for dealing with text in charts, document paragraphs and embedded spreadsheets.  If I were to design it, this shared functionality would be abstracted to its own namespace.  I want to be able to write clean, reusable code.

Ultimately the teams within the Office suite need to start working together the way that the language teams have begun to do within Visual Studio.  The same tagging tools should be available in Word, PowerPoint, Excel and OneNote and they should be represented the same in the XML that is rendered.