4

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?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Vincent Hogendoorn
  • 700
  • 1
  • 7
  • 23
  • 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 Jul 31 '14 at 10:52
  • 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: ` ` 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 Jul 31 '14 at 11:03
  • 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 Jul 31 '14 at 11:11
  • 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 Jul 31 '14 at 11:48
  • 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 Jul 31 '14 at 11:57

1 Answers1

11

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

petelids
  • 12,305
  • 3
  • 47
  • 57
  • I did find the additional style, which I already mentioned in one of the comments.. I didn't really want to HardCode these 'standard' styles because the're available in Word, but too bad these default styles aren't written to the document by default. Thanks for your reaction, I'll create the styles by myself. – Vincent Hogendoorn Jul 31 '14 at 12:07
  • Sorry, I hadn't seen your last comment. That is of course the other way to do it; use the style in your source file then the style will exist in styles.xml and you can reference the style without having to create it yourself. – petelids Jul 31 '14 at 12:10
  • Yes, but clicking all the default styles was only for testing. The problem is that our clients can create a template with styles by themselves (and use classes in the html to use these styles), but if they didn't specify classes and styles I want to use the default styles. But I can't assume our clients click every default style so it will be added. So I've to specify them by myself. No problem, just a little more work then expected and hoped. – Vincent Hogendoorn Jul 31 '14 at 12:14
  • 1
    @VincentHogendoorn - see my edit. That should reduce the amount of work required. – petelids Aug 01 '14 at 08:38
  • thank you very much! Vote up for the addition. This really helps me and indeed reduces the amount of work required :) – Vincent Hogendoorn Aug 01 '14 at 09:50
  • Did you also opened the document in LibreOffice? Because when I now open my document in Word, it indeed uses the styles as wanted, but now if I open the document it's all messed up. This is probably because of Libre Office, because if I comment out the code for loading the styles everything looks fine. – Vincent Hogendoorn Aug 04 '14 at 14:48