4
votes

I'm working on an export of an HTML file to a Open XML wordfile. If in the HTML <h1> is used, I want to add a Heading1 style to that part. But somehow when I open the document in Microsoft Word 2010, the Style isn't applied.

If I open the created document in Libre Office, there is some style applied.

I also defined some styles myself, and if I use one of those styles, everything went well in Word and Libre Office.

I opened the Open XML SDK 2.5 Productivity Tool for Microsoft Office and when I look in the example code it provides, it suggests:

ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId(){ Val = "Kop1" };

Kop1 (instead of Heading1) is because my Word is in Dutch so my template is in Dutch, but this didn't solve the problem.

In this code sample I create the paragraph and add style and text to it:

using (wordDocument = WordprocessingDocument.Open(documentStream, true)) 
{
    MainDocumentPart mainPart = wordDocument.MainDocumentPart;
    WP.Body body = wordDocument.MainDocumentPart.Document.Body;
    WP.Paragraph para = body.AppendChild(new WP.Paragraph());
    StyleDefinitionsPart part = wordDocument.MainDocumentPart.StyleDefinitionsPart;
    if (part != null)
    {
        WP.ParagraphProperties pPr = new WP.ParagraphProperties();
        WP.ParagraphStyleId paragraphStyleId1 = new WP.ParagraphStyleId() { Val = "Heading1" };
        pPr.Append(paragraphStyleId1);

        para.Append(pPr);
    }

    WP.Run run = para.AppendChild(new WP.Run());
    run.AppendChild(new WP.Text(value));
}

It has styles defined, because I work with a template, so the code will come inside the if-statement.

I also tried it with the style title (in Dutch titel), tried both but both didn't work...

I really don't understand what's wrong and why I can use my own created styles but can't use one of the predefined styles of Word, which I didn't remove in the template.

It somehow doesn't recognize the predefined styles?

EDIT/ADDITION

I got it working, but not the way I want, I have to click on the predefined styles in the template-document and then save the document. Somehow now after clicking them and saving these styles are added to the document, because if I now generate my final document using the template, I can use the styles. But without clicking the styles in the document first, I can't use them becuase they aren't saved?

1
Just to clarify, the productivity tool showed your Heading1 style name as Kop1 and you've tried using this in your actual code i.e. WP.ParagraphStyleId paragraphStyleId1 = new WP.ParagraphStyleId() { Val = "Kop1" };? Can you post the reflection of your actual document (generated, not template) with just a heading in along with actually using word to open your template file and saving out the same type of doc (with just a heading in) and posting the reflection of that too?Paul Aldred-Bann
Yes I indeed tried using WP.ParagraphStyleId paragraphStyleId1 = new WP.ParagraphStyleId() { Val = "Kop1" }; I also reflected the files what you suggest, and somehow the style: ` <w:style w:type="paragraph" w:styleId="Kop1"> ` is added in the document I created with Word, and this is missing in the generated document. But I don't understand, because it's a default style I can select in Word.Vincent Hogendoorn
Two further questions - what is documentStream is that a File.Open of your template docx? Also, in StyleDefinitionsPart part = wordDocument.MainDocumentPart.StyleDefinitionsPart; what does part contain? Edit - I've just tried your code with one of my templates, and it's working fine, so we're definitely on a style name / doc type issue here.Paul Aldred-Bann
The documentStream is a memoryStream which the document is saved. First I open the templateDocument and save it as the docuementStream. After that I can add everything I want and finally convert the stream so I can download it as an attachment. The styleDefinitionsPart part contains all the styles of the document. Because if I don't use a template but an empty document, there isn't a StyleDefinitionsPart in the document and it should be created. I'll try again with a new Template, maybe something is wrong in the templatefile..Vincent Hogendoorn
I got it working, but not the way I want, I have to select the Heading1 (Kop1) in the word-template first and then save the template. After that, if I use this template to generate my document, it uses the Heading1 (Kop1) style. So predefined styles in Word aren't directly saved in the styles.xml, only after selecting them?Vincent Hogendoorn

1 Answers

8
votes

Unfortunately this happens because the Style is not written to the document by default (even though it is "built-in" to Word) therefore the style is not applied.

If you create a document via your code and then another via Word with the Heading1 style applied then compare the XML in \word\styles.xml you will see there is an additional section in the Word generated XML:

enter image description here

You can generate your own style information using the following code. I don't know of a way to grab these styles from somewhere other than hardcoding; perhaps they could be found in a dotx file somewhere? See edit below for more on this

using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(documentStream, true))
{
    MainDocumentPart mainPart = wordDocument.MainDocumentPart;
    Body body = wordDocument.MainDocumentPart.Document.Body;
    Paragraph para = body.AppendChild(new Paragraph());
    StyleDefinitionsPart part = wordDocument.MainDocumentPart.StyleDefinitionsPart;
    if (part != null)
    {
        Style style = new Style()
        {
            Type = StyleValues.Paragraph,
            StyleId = "Heading1",
            BasedOn = new BasedOn() { Val = "Normal" },
            NextParagraphStyle = new NextParagraphStyle() { Val = "Normal" }
        };

        StyleName styleName1 = new StyleName() { Val = "heading 1" };
        style.Append(styleName1);
        style.Append(new PrimaryStyle());
        StyleRunProperties styleRunProperties1 = new StyleRunProperties();
        styleRunProperties1.Append(new Bold());
        styleRunProperties1.Append(new RunFonts() 
            {
                ComplexScriptTheme=ThemeFontValues.MajorBidi, 
                HighAnsiTheme=ThemeFontValues.MajorHighAnsi,
                EastAsiaTheme=ThemeFontValues.MajorEastAsia, 
                AsciiTheme=ThemeFontValues.MajorAscii 
            });
        styleRunProperties1.Append(new FontSize() { Val = "28" });
        styleRunProperties1.Color = new Color() 
            {
                Val = "365F91",
                ThemeShade = "BF",
                ThemeColor = ThemeColorValues.Accent1
            };
        style.Append(styleRunProperties1);
        part.Styles.Append(style);

        ParagraphProperties pPr = new ParagraphProperties();
        ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "Heading1" };
        pPr.Append(paragraphStyleId1);
        para.Append(pPr);
    }

    Run run = para.AppendChild(new Run());
    run.AppendChild(new Text("This is a heading"));
}

Edit

I had a look at this and found that the Word default styles are indeed stored in .dotx files as I guessed above. Those files are readable via the OpenXML API as well so it's possible to copy the styles from there into your document. The code for this is very similar to the code we already have with the addition of reading the Default.dotx file and grabbing the styles from there.

On my system the dotx files are in C:\Program Files\Microsoft Office\Office14\1033\QuickStyles which I've hard coded below. I don't know if there is somewhere this can be picked up dynamically (the registry perhaps) but if not I guess a config file will have to suffice.

using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(documentStream, true))
{
    MainDocumentPart mainPart = wordDocument.MainDocumentPart;
    Body body = wordDocument.MainDocumentPart.Document.Body;
    Paragraph para = body.AppendChild(new Paragraph());
    Paragraph para2 = body.AppendChild(new Paragraph());
    Paragraph para3 = body.AppendChild(new Paragraph());

    StyleDefinitionsPart part = wordDocument.MainDocumentPart.StyleDefinitionsPart;
    if (part != null)
    {
        //I'm looping the styles and adding them here
        //you could clone the whole StyleDefinitionsPart
        //but then you'd lose custom styles in your source doc
        using (WordprocessingDocument wordTemplate = WordprocessingDocument.Open(@"C:\Program Files\Microsoft Office\Office14\1033\QuickStyles\default.dotx", false))
        {
            foreach (var templateStyle in wordTemplate.MainDocumentPart.StyleDefinitionsPart.Styles)
            {
                part.Styles.Append(templateStyle.CloneNode(true));
            }
        }

        //I can now use any built in style 
        //I'm using Heading1, Title and IntenseQuote as examples
        //You may need to do a language conversion here as 
        //you mentione your docx is in Dutch
        ParagraphProperties pPr = new ParagraphProperties();
        ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "Heading1" };
        pPr.Append(paragraphStyleId1);
        para.Append(pPr);

        Run run = para.AppendChild(new Run());
        run.AppendChild(new Text("This is a heading"));

        ParagraphProperties pPr2 = new ParagraphProperties();
        ParagraphStyleId paragraphStyleId2 = new ParagraphStyleId() { Val = "Title" };
        pPr2.Append(paragraphStyleId2);
        para2.Append(pPr2);

        Run run2 = para2.AppendChild(new Run());
        run2.AppendChild(new Text("This is a title"));

        ParagraphProperties pPr3 = new ParagraphProperties();
        ParagraphStyleId paragraphStyleId3 = new ParagraphStyleId() { Val = "IntenseQuote" };
        pPr3.Append(paragraphStyleId3);
        para3.Append(pPr3);

        Run run3 = para3.AppendChild(new Run());
        run3.AppendChild(new Text("This is an intense quote"));
    }
}

The file this produces looks like this:

enter image description here