Unable to use existing paragraph styles in Open Xm

2019-01-12 10:44发布

问题:

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:

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:

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: