Breaking Changes in the Open XML SDK v2 April 2009 CTP

One of the big changes we made in the Open XML SDK v2 April 2009 CTP was improving the Low Level DOM component to include functionality related to Office 2007 SP2. With this improvement came a difference in how some elements were interpreted as a 1st class property of a parent class/element vs. as a child element. For example, SdtProperties is no longer a property off of the SdtXXX classes, but is rather interpreted as just a child element. Scouring through the different customer feedback channels, the Open XML SDK forum, www.openxmldeveloper.org, and the SDK Connect site, I've noticed that this change broke some of my previous posts and code samples. In today's post, I am going to show you a workaround to this issue and I'm going to point you to April 2009 CTP complaint versions of sample code that is currently broken.

SdtBlock does not contain a definition for SdtProperties

Many of my Word related SDK posts leverage content controls as semantic structure. In my posts, I show you how to use these content controls to easily find content or add content to a specific area. In many of these posts I used the following code snippet construct:

SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>()

.Where(s => s.SdtProperties.GetFirstChild<Alias>().Val.Value

.Equals(sdtName)).First();

If you try to compile the above code snippet in the latest CTP of the SDK you will get the following compiler error:

'DocumentFormat.OpenXml.Wordprocessing.SdtBlock' does not contain a definition for 'SdtProperties' and no extension method 'SdtProperties' accepting a first argument of type 'DocumentFormat.OpenXml.Wordprocessing.SdtBlock' could be found (are you missing a using directive or an assembly reference?)

To resolve this error you need to get access to SdtProperties as child element rather than a property. This task can be accomplished with the following code snippet:

SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>()

.Where(s =>

s.GetFirstChild<SdtProperties>().GetFirstChild<Alias>().Val.Value

.Equals(sdtName)).First();

SdtBlock does not contain a definition for SdtContentBlock

Similarly to the issue with SdtProperties, SdtContentBlock was moved to be a child element rather than a property. You will need to change the following code snippet from:

Paragraph p = sdt.SdtContentBlock.GetFirstChild<Paragraph>();

To:

Paragraph p = sdt.GetFirstChild<SdtContentBlock>().GetFirstChild<Paragraph>();

Here are links to fixed versions of previous solutions that were broken due to April 2009 CTP changes:

Solution

Fixed Code Sample Link

Import tables from Word to Excel

Click here

Import charts from Excel to Word

Click here

Feedback

We are currently looking into improving our SDK behavior to re-include some of the lost functionality of not seeing some elements as 1st class properties. Stay tuned for an update.

I also wanted to take this time to thank you guys for all your feedback. Keep sending it our way.

Thanks,

Zeyad Rajabi

Comments

  • Anonymous
    May 19, 2009
    PingBack from http://asp-net-hosting.simplynetdev.com/breaking-changes-in-the-open-xml-sdk-v2-april-2009-ctp/

  • Anonymous
    May 25, 2009
    Brian, I am struggling to find a solution to an issue that I am having that is relevant to your blogs.  I am trying to to get a cells background color value.  This is not at all straight forward and a sample code would go a long way.  I don't understand how to access this information?  Is this embedded in the sytles.xml and somehow this has a per-cell relation to the cell of interest?  Your expertise on shedding some light on this issue would be so great. Many thanks, Adam

  • Anonymous
    May 26, 2009
    Adam, Are you interested in figuring out the cell background color for Excel or Word files?

  • Anonymous
    May 27, 2009
    Fine Thanks, But a get NullPointerException with, SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>() .Where(s => s.GetFirstChild<SdtProperties>().GetFirstChild<Alias>().Val.Value .Equals(sdtName)).First(); I maked my self method private static SdtBlock GetSdtBlock(OpenXmlElement row, string tagName) {    IEnumerable<SdtBlock> sdtBlocks = row.Descendants<SdtBlock>();    foreach (SdtBlock sdtBlock in sdtBlocks) {        IEnumerable<SdtProperties> sdtProperties = sdtBlock.Descendants<SdtProperties>();        foreach (SdtProperties sdtProperty in sdtProperties) {            IEnumerable<Tag> tags = sdtProperty.Descendants<Tag>();            foreach (Tag tag in tags) {                if (tag.Val.Value == tagName) {                    return sdtBlock;                }            }        }    }    return null; }

  • Anonymous
    May 27, 2009
    As you noted in your code sample, you get the null exception if you have a content control that doesn't have the specified child element. You can workaround this issue by checking to see if the child element is null. If not, then you can check it's children.