OpenXML document style inheritance
The biggest challenge I encountered when writing an object model for OOXML documents was handling inheritance.
WordprocessingML has a relatively complex inheritance hierarchy (illustrated for the most part in the diagram below) and it was a struggle to come up with a solution that would be both quick to implement for every property across the entire model, and yet be flexible enough to handle every situation and edge case.
Fortunately I was able to leverage one of my favorite features of OpenXML, property elements, and come up with a quick and (IMO [:)]) simple solution.
Property elements
OpenXML has a standard approach to defining data and meta-data for an element. Rather than embedding information in attributes directly against the element, OpenXML's approach is to separate the information into a child properties element. For example a run element (<r>) has its data defined in a run properties element (<rPr>), a paragraph element (<p>) has paragraph properties (<pPr>), a table cell element (<tc>) has table cell properties (<tcPr>), etc, etc.
<w:r>
<w:rPr>
<w:b />
<w:szw:val="52" />
<w:rFontsw:ascii="Cambria" />
</w:rPr>
<w:t>OpenXML document style inheritance</w:t>
</w:r>
Property elements are reused throughout the specification. Run properties for example can be defined directly against a run like the example above, but can also appear in a style element and in the document itself as the document defaults. The appearance of a piece of text is then determined by looking at this hierarchy properties and using the first value it encounters, from direct formatting first to document defaults last.
Inheritance solution
I found the property element approach quite beneficial when writing an object model. Reusing property classes was one benefit but I also found the approach useful when implementing inheritance.
Since the hierarchy is made up of the same object repeated in different places, e.g. run properties directly against a run, run properties on a style, document default run properties, I simply wrote a method which took a delegate for getting a value from the properties object and then ran that against each object in the hierarchy until a non-null value was returned.
public T GetValue<T>(Func<RunProperties, T> valueGetter)
{
// execute delegate against each RunProperties
// in inheritance hierarchy until a value is returned
}
public Unit? FontSize
{
get { return GetValue(p => p._fontSize); }
set { _fontSize = value; }
}
So far this solution has worked well for me and it has handled the various edge cases in OOXML.