Testing for Base Styles in Open XML WordprocessingML Documents

Sometimes you want to process all paragraphs in a document, and filter based on the style name.  However, sometimes it isn’t good enough to just filter on the style name, because if another style inherits from the style of interest, you want to include it in your processing.  A common example is that you want to process all paragraphs that are styled as “Heading1”, and all paragraphs that have a style that is based on “Heading1”.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCThe following example shows how to iterate through a document, and test whether each paragraph is styled as “Heading1” or one derived from it.  The StyleChainReverseOrder method is an iterator that returns a collection of styles in the style chain; however, the styles in the returned collection are in most-derived to least-derived order.  The StyleChain method returns the collection from least-derived to most-derived, which most often is the order that you want to process them.  In this case, it doesn't really matter, but in others it does, so I included both methods in this post.  The interesting method in this post is the IsStyleBasedOnStyle method.  You can pass two style names to the IsStyleBasedOnStyle method, and it returns true if the style in the styleId argument is based on the style in the basedOnStyleId style.  This example uses the strongly-typed OM, but it's pretty easy to convert to use LINQ to XML if that is what you are using.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

class Program
{
static IEnumerable<Style> StyleChainReverseOrder(WordprocessingDocument doc,
string styleId)
{
string current = styleId;
while (true)
{
Style style = doc.MainDocumentPart.StyleDefinitionsPart.Styles
.Elements<Style>().Where(s => s.StyleId == current)
.FirstOrDefault();
yield return style;
if (style.BasedOn == null)
yield break;
current = style.BasedOn.Val;
}
}

static IEnumerable<Style> StyleChain(WordprocessingDocument doc,
string styleId)
{
return StyleChainReverseOrder(doc, styleId).Reverse();
}

static bool IsStyleBasedOnStyle(WordprocessingDocument doc, string styleId,
string basedOnStyleId)
{
return StyleChain(doc, styleId).Any(s => s.StyleId.Value == basedOnStyleId);
}

static void Main(string[] args)
{
using (WordprocessingDocument doc =
WordprocessingDocument.Open("Test.docx", false))
{
int cnt = 1;
foreach (var p in doc.MainDocumentPart.Document.Body.Elements<Paragraph>())
{
Console.WriteLine("Paragraph: {0}", cnt++);
if (p.ParagraphProperties != null)
{
Console.WriteLine("StyleID: {0}",
p.ParagraphProperties.ParagraphStyleId.Val);
foreach (var s in StyleChain(doc,
p.ParagraphProperties.ParagraphStyleId.Val))
Console.WriteLine(" {0}", s.StyleId.Value);
Console.WriteLine(" Is Based on Heading1: {0}",
IsStyleBasedOnStyle(doc,
p.ParagraphProperties.ParagraphStyleId.Val, "Heading1"));
}
Console.WriteLine();
}
}
}
}