15

I'm creating a docx generator with POI and would like to use predefined formats.

Word includes several formats like Title, Heading 1..10 etc. These formats are predefined in every DOCX you create with Word.

I would like to use them in my docx generator. I tried the following but the format was not applied:

paragraph = document.createParagraph();
lastParagraph.setStyle("Heading1");

I also tried "heading 1", "heading1" and "Heading1" as style, but none of them worked.
The API documentation doesn't show any details.

I analysed a docx file created with Word 2007 and found out "Heading1" would be correct. Unfortunately, the style is not defined in the docx. Do I have to create this style manually?

Can anyone point me to the correct solution?

Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186
guerda
  • 23,388
  • 27
  • 97
  • 146

4 Answers4

20

It's very simple: Use a "template" docx file.

  1. Create an empty docx file with Word 2007.
  2. Use this file as a template for your XWPFDocument
  3. Add your paragraphs with the styles.

Here's the code:

XWPFDocument document = new XWPFDocument(new FileInputStream("template.docx");
paragraph = document.createParagraph();
paragraph.setStyle("Heading1");

The template contains all styles and therefore they can referenced via setStyle("Heading1");.

guerda
  • 23,388
  • 27
  • 97
  • 146
  • 5
    this works great! But there's a caveat... It appears word discards unused styles from the template document. You'll need to have existing text in the document using those Styles, or use a template somehow... – Jonathan S. Fisher Apr 23 '12 at 14:52
  • 1
    @exabrial You are right, unless we add styles in template, not getting styles. thanks. It helped me alot and saved alot of time – MaheshVarma Jul 25 '13 at 07:42
  • @guerda I might be not fully aware. but what is `lastParagraph` means here? – pulse Mar 02 '16 at 07:01
  • @pulse Wow, 6 year old code and nobody noticed the error! Of course I meant just `paragraph`. Thanks for the hint! – guerda Mar 02 '16 at 13:36
9

You can create a word template (just use the Save as... feature in Word).

first option

The template now contains a number of additional XML files in \word folder: - styles.xml - stylesWithEffects.xml - webSettings.xml - fontTable.xml and a - \theme folder

If you copy those files into your original POI generated file then you can reference styles given in the styles.xml file.

You can manipulate your original file like a ZIP file, this shouldn't be to much effort.

second option

Copy styles in code from template to your document:

XWPFDocument template = new XWPFDocument(new FileInputStream(new File("Template.dotx")));       

XWPFDocument doc = new XWPFDocument();      
// let's copy styles from template to new doc
XWPFStyles newStyles = doc.createStyles();
newStyles.setStyles(template.getStyle());


XWPFParagraph para = doc.createParagraph();
para.setStyle("Heading1");

XWPFRun run = para.createRun();
run.setText("Heading 1");

return doc;

On the plus side you can manipulate your styles separately directly using Word and saving them back to the template file.

Drejc
  • 14,196
  • 16
  • 71
  • 106
8

If you are generally interested in creating a style that is recognized as a level 1 heading (e.g., for use in an MS Word-generated TOC) and can be accessed in the Word formats bar, it can be done like this:

private static File writeSimpleDocxFile(String content) throws IOException {
    XWPFDocument docxDocument = new XWPFDocument();

    String strStyleId = "ownstyle1";

    addCustomHeadingStyle(docxDocument, strStyleId, 1);

    XWPFParagraph paragraph = docxDocument.createParagraph();
    XWPFRun run = paragraph.createRun();
    run.setText(content);

    paragraph.setStyle(strStyleId);
}

private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {

    CTStyle ctStyle = CTStyle.Factory.newInstance();
    ctStyle.setStyleId(strStyleId);

    CTString styleName = CTString.Factory.newInstance();
    styleName.setVal(strStyleId);
    ctStyle.setName(styleName);

    CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
    indentNumber.setVal(BigInteger.valueOf(headingLevel));

    // lower number > style is more prominent in the formats bar
    ctStyle.setUiPriority(indentNumber);

    CTOnOff onoffnull = CTOnOff.Factory.newInstance();
    ctStyle.setUnhideWhenUsed(onoffnull);

    // style shows up in the formats bar
    ctStyle.setQFormat(onoffnull);

    // style defines a heading of the given level
    CTPPr ppr = CTPPr.Factory.newInstance();
    ppr.setOutlineLvl(indentNumber);
    ctStyle.setPPr(ppr);

    XWPFStyle style = new XWPFStyle(ctStyle);

    // is a null op if already defined
    XWPFStyles styles = docxDocument.createStyles();

    style.setType(STStyleType.PARAGRAPH);
    styles.addStyle(style);

}

Yes, this style will show up in the styles.xml.

(I know: This is not a direct answer to your question, but as I did not find this info on the internet in a usable form, I'll post it here)

RobertG
  • 1,550
  • 1
  • 23
  • 42
  • How can I set a font on this custom style? – Rob Audenaerde Apr 15 '16 at 12:12
  • While I currently cannot look this up in the software anymore, I did a quick search. The POI javadocs have no reference to CT style, alas ( https://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFDocument.html ), but the office open website has some pointers: https://wiki.openoffice.org/wiki/Cell_Style_in_Xls_module – RobertG Apr 15 '16 at 12:44
  • It seems if you can set fonts on XWPFStyles: https://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFStyles.html#setDefaultFonts(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts) – RobertG Apr 15 '16 at 12:48
2

Yes, you should do it manually. Docx spec says that styles.xml which contains info about styles is optional. So, I almost sure that POI doesn't create it at all if you do not do it explicitely. You can check it: just unzip docx file and look whether this file is there or not (yourfile.docx/word/styles.xml).

So, what you should do (in docx terms, I don't know how that's implemented in POI):

1) create styles.xml and add necessary styles there

2) create relationship which connects document.xml and styles.xml (I think POI should do it automatically)

3) use styles ids inside document.xml to connect concrete text part (Run in docx terms) with concrete style.

Roman
  • 64,384
  • 92
  • 238
  • 332
  • Thanks for your answer! Your solution would be a huge effort to manually reproduce the styles. – guerda Apr 15 '10 at 11:24