Apache POI Word using custom styles for titles - java

I am trying to create heading titles in a word (.docx) document, using apache-poi.
I have a template which contains only custom styles AND example of heading titles using the custom styles.
XWPFDocument document=new XWPFDocument(new FileInputStream("template.docx"));
My custom style is called "CUSTOM_YNP" (I created it directly in Word), but when I use the line below, it returns false
document.getStyles().styleExist("CUSTOM_YNP")
And, of course, when I try to use this style, it doesn't work, actually it print my string in "Normal" style
XWPFParagraph paragraph=document.createParagraph();
paragraph.setStyle("CUSTOM_YNP");
XWPFRun run=paragraph.createRun();
run.setText("TEST");
Just for the record, my "save document" line :
document.write(new FileOutputStream("myDoc.docx"));
I have read this question, but can't actually find a solution to my problem... How can I use predefined formats in DOCX with POI?
EDIT : It works if I create my own style using Apache-POI.... Still I woudl really like to use existing styles from the word document.

A *.docx is a ZIP archive. You can unzip it and look into the /word/styles.xml. There you will see that the w:styleId="CUSTOMYNP" without the underscore. The name is "CUSTOM_YNP" <w:name w:val="CUSTOM_YNP"/>. So:
XWPFDocument document = new XWPFDocument(new FileInputStream("template.docx"));
System.out.println(document.getStyles().styleExist("CUSTOMYNP"));
System.out.println(document.getStyles().getStyle("CUSTOMYNP").getName());
XWPFParagraph paragraph=document.createParagraph();
paragraph.setStyle("CUSTOMYNP");
XWPFRun run=paragraph.createRun();
run.setText("TEST");
document.write(new FileOutputStream("myDoc.docx"));
document.close();

Make sure you first create the Style and add it to your document:
XWPFDocument document = new XWPFDocument();
XWPFStyles styles = document.createStyles();
String heading1 = "My Heading 1";
addCustomHeadingStyle(document, styles, heading1, 1, 36, "4288BC");
XWPFParagraph paragraph = document.createParagraph();
paragraph.setStyle(heading1);
With the addCustomHeadingStyle being:
private static void addCustomHeadingStyle(XWPFDocument docxDocument, XWPFStyles styles, String strStyleId, int headingLevel, int pointSize, String hexColor) {
CTStyle ctStyle = CTStyle.Factory.newInstance();
...
//create your style
...
XWPFStyle style = new XWPFStyle(ctStyle);
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}

Related

How to use the POI to cancel the automatic adjustment of the spacing between Chinese and western languages in word paragraphs

I use XWPFDocument and XWPFParagraph class to create a Word, But there is always a gap between Chinese and Western, I cancel the automatic adjustment of the spacing between Chinese and western languages in word paragraphs through WORD can solve the problem, but how can I do that useing code;
I think can use CTStyle, but I don't know how to do that;
XWPFDocument doc = new XWPFDocument();
XWPFParagraph page = doc.createParagraph();
XWPFRun runs = page.createRun();
runs.setBold(false);
runs.setFontFamily("宋体");
runs.setFontSize(9);
runs.setText("12H型");
//export
OutputStream output = response.getOutputStream();
BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output);
bufferedOutPut.flush();
doc.write(bufferedOutPut);
bufferedOutPut.close();
I suspect you mean the settings described in Configure text spacing between East Asian and Latin text.
Those settings are stored in document.xml using the elements autoSpaceDEand autoSpaceDN in paragraph properties.
Using apache poi this could be done like so:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
public class CreateWordEnglishAndChinese {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
if (paragraph.getCTP().getPPr() == null) paragraph.getCTP().addNewPPr();
if (paragraph.getCTP().getPPr().getAutoSpaceDE() == null) paragraph.getCTP().getPPr().addNewAutoSpaceDE();
paragraph.getCTP().getPPr().getAutoSpaceDE().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff.OFF);
if (paragraph.getCTP().getPPr().getAutoSpaceDN() == null) paragraph.getCTP().getPPr().addNewAutoSpaceDN();
paragraph.getCTP().getPPr().getAutoSpaceDN().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff.OFF);
XWPFRun run = paragraph.createRun();
run.setText("12H型:Type 12H");
FileOutputStream out = new FileOutputStream("CreateWordEnglishAndChinese.docx");
document.write(out);
out.close();
document.close();
}
}

Generate Inter-Document Hyperlink with Apache POI in Java

I'm generating an XWPFDocument with Apache POI (never used it before this) and I'd like to link one paragraph to another paragraph inside the same .docx document. Is this possible using POI's native functionality or do I need to deep-dive into XML Bean wrapper classes (i.e. CTP) to hand-jam this or am I out of luck? Every instance of a question regarding hyperlinks and POI that I have seen references creating either an external-type hyperlink or a link between Excel workbook sheets. I am as of now only able to generate a 'hyperlink' in the sense of ctrl-clicking the paragraph inside the finished document and it appears to simply do a text search starting from the top of the document. Here's the code I am currently using to achieve this. Thanks in advance!
public static void addInternalHyperlink(XWPFParagraph origin, String text, XWPFParagraph target) {
if (target != null) {
// Create the hyperlink itself
CTHyperlink link = origin.getCTP().addNewHyperlink();
link.setAnchor(target.getText());
// Create hyperlink text
CTText linkText = CTText.Factory.newInstance();
linkText.setStringValue(text);
CTR ctr = CTR.Factory.newInstance();
ctr.setTArray(new CTText[] {linkText});
// Format hyperlink text
CTFonts fonts = CTFonts.Factory.newInstance();
fonts.setAscii("Times New Roman");
CTRPr rpr = ctr.addNewRPr();
CTColor color = CTColor.Factory.newInstance();
color.setVal("0000FF");
rpr.setColor(color);
CTRPr rpr1 = ctr.addNewRPr();
rpr1.addNewU().setVal(STUnderline.SINGLE);
// Insert formatted text into link
link.setRArray(new CTR[] {ctr});
}
}
Please note that I'd like to use the 'origin' argument as the paragraph containing the actual link, the 'text' argument as the link text, and the 'target' argument as the actual link destination.
UPDATE: Here's an XML snippet containing a sample paragraph which I have linked to a section heading via the Word GUI.
<w:p w14:paraId="5B1C3A0C" w14:textId="659E388D" w:rsidR="00A4419C" w:rsidRDefault="00A4419C" w:rsidP="00A4419C"><w:hyperlink w:anchor="_Another_Heading" w:history="1"><w:r w:rsidRPr="00A4419C"><w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr><w:t>Here is some stuff that could b</w:t></w:r><w:r w:rsidRPr="00A4419C"><w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr><w:t>e</w:t></w:r><w:r w:rsidRPr="00A4419C"><w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr><w:t xml:space="preserve"> the link</w:t></w:r></w:hyperlink></w:p><w:p w14:paraId="19996B78" w14:textId="5C39B081" w:rsidR="00A4419C" w:rsidRPr="00A4419C" w:rsidRDefault="00A4419C" w:rsidP="00A4419C"><w:pPr><w:pStyle w:val="Heading1"/></w:pPr><w:bookmarkStart w:id="0" w:name="_Another_Heading"/><w:bookmarkEnd w:id="0"/><w:r><w:t>Another Heading</w:t></w:r><w:bookmarkStart w:id="1" w:name="_GoBack"/><w:bookmarkEnd w:id="1"/></w:p>
The solution falls into two parts.
First we need a XWPFHyperlinkRun whose target is an anchor in the document.
Second we need that target anchor, which can be a bookmark in the document for example. So we need creating such bookmark in the document.
Unfortunately both is not supported using only high level classes of apache poi until now. So we need the low level classes form ooxml-schemas too.
The following code works using apache poi 4.0.0 together with ooxml-schemas-1.4.
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
import java.math.BigInteger;
public class CreateWordHyperlinkBookmark {
static XWPFHyperlinkRun createHyperlinkRunToAnchor(XWPFParagraph paragraph, String anchor) throws Exception {
CTHyperlink cthyperLink=paragraph.getCTP().addNewHyperlink();
cthyperLink.setAnchor(anchor);
cthyperLink.addNewR();
return new XWPFHyperlinkRun(
cthyperLink,
cthyperLink.getRArray(0),
paragraph
);
}
static XWPFParagraph createBookmarkedParagraph(XWPFDocument document, String anchor, int bookmarkId) {
XWPFParagraph paragraph = document.createParagraph();
CTBookmark bookmark = paragraph.getCTP().addNewBookmarkStart();
bookmark.setName(anchor);
bookmark.setId(BigInteger.valueOf(bookmarkId));
XWPFRun run = paragraph.createRun();
paragraph.getCTP().addNewBookmarkEnd().setId(BigInteger.valueOf(bookmarkId));
return paragraph;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
String anchor = "hyperlink_target";
int bookmarkId = 0;
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("This is a text paragraph having ");
//create hyperlink run
XWPFHyperlinkRun hyperlinkrun = createHyperlinkRunToAnchor(paragraph, anchor);
hyperlinkrun.setText("a link to an bookmark anchor");
hyperlinkrun.setColor("0000FF");
hyperlinkrun.setUnderline(UnderlinePatterns.SINGLE);
run = paragraph.createRun();
run.setText(" in it.");
//some empty paragraphs
for (int i = 0; i < 10; i++) {
paragraph = document.createParagraph();
}
//create bookmarked paragraph as the hyperlink target
paragraph = createBookmarkedParagraph(document, anchor, bookmarkId++);
run = paragraph.getRuns().get(0);
run.setText("This is the target.");
FileOutputStream out = new FileOutputStream("CreateWordHyperlinkBookmark.docx");
document.write(out);
out.close();
document.close();
}
}

For Text, Appending is not happening in word doc (.docx) in Java Code

I have tried using below code to append the content present in word doc:
XWPFDocument doc=new XWPFDocument();
XWPFParagraph para=doc.createParagraph();
XWPFRun run=para.createRun();
File f=new File("Text.docx");
FileOutputStream fos=new FileOutputStream(f, true);
run.setText("Append The value please");
doc.write(fos);
But, after completion of program, when I try to open the file, it says "We're sorry. We can't open the file. We found a problem with its content" .
I am using below jars:
1. Poi 3.12
2. Poi -ooxml-3.10.1
3. Poi-scratchpad-3.15
4. Ooxml-schemas-1.1
5. Xmlbeans-2.3.0
6. Dom4j-1.1
what is the reason of this & what could be the solution to avoid this?
It is because, you are not opening the file using Apache POI.
Use XWPFDocument to open the word document to append data. Pfb the code.
XWPFDocument doc = new XWPFDocument(OPCPackage.open(fileLocationPath + "Document.doc"));
List<XWPFParagraph> paragraphs = doc.getParagraphs();
XWPFParagraph paragraph = paragraphs.get(paragraphs.size() - 1);
XWPFRun runText = paragraph.createRun();
//if you want to add text
runText.setText("appending here");
//if you want to add image
runText.addPicture(java.io.InputStream pictureData, int pictureType, java.lang.String filename, int width, int height)
try (FileOutputStream out = new FileOutputStream(fileLocationPath + "Document.doc")) {
doc.write(out);
} catch (IOException e) {
e.printStackTrace();
}
if you want to add image - use addPicture Method of XWPFRun - refer here - Apache POI XWPFRun Add Picture

How to set background color (Page Color) for word document (.doc or .docx) in Java?

By some libraries like http://poi.apache.org , we could create word document with any text color, but for background or highlight of the text, I didn't find any solution.
Page color for word in manual way!:
https://support.office.com/en-us/article/Change-the-background-or-color-of-a-document-6ce0b23e-b833-4421-b8c3-b3d637e62524
Here is my main code to create word document by poi.apache
// Blank Document
#SuppressWarnings("resource")
XWPFDocument document = new XWPFDocument();
// Write the Document in file system
FileOutputStream out = new FileOutputStream(new File(file_address));
// create Paragraph
XWPFParagraph paragraph = document.createParagraph();
paragraph.setAlignment(ParagraphAlignment.RIGHT);
XWPFRun run = paragraph.createRun();
run.setFontFamily(font_name);
run.setFontSize(font_size);
// This only set text color not background!
run.setColor(hex_color);
for (String s : text_array) {
run.setText(s);
run.addCarriageReturn();
}
document.write(out);
out.close();
Update: XWPF is the newest way to create word document files, but setting background only possible by HWPF which is for old format version (.doc)
For *.doc (i.e. POI's HWPF component):
Highlighting of text:
Look into setHighlighted()
Background color:
I suppose you mean the background of a paragraph (AFAIK, Word also allows to color the entire page which is a different matter)
There is setShading() which allows you to provide a foreground and background color (through setCvFore() and setCvBack() of SHDAbstractType) for a Paragraph. IIRC, it is the foreground that you would want to set in order to color your Paragraph. The background is only relevant for shadings which are composed of two (alternating) colors.
The underlying data structure is named Shd80 ([MS-DOC], 2.9.248). There is also SHDOperand ([MS-DOC], 2.9.249) that reflects the functionality of Word prior to Word97. [MS-DOC] is the Binary Word File format specification which is freely available on MSDN.
Edit:
Here is some code to illustrate the above:
try {
HWPFDocument document = [...]; // comes from somewhere
Range range = document.getRange();
// Background shading of a paragraph
ParagraphProperties pprops = new ParagraphProperties();
ShadingDescriptor shd = new ShadingDescriptor();
shd.setCvFore(Colorref.valueOfIco(0x07)); // yellow; ICO
shd.setIpat(0x0001); // solid background; IPAT
pprops.setShading(shd);
Paragraph p1 = range.insertBefore(pprops, StyleSheet.NIL_STYLE);
p1.insertBefore("shaded paragraph");
// Highlighting of individual characters
Paragraph p2 = range.insertBefore(new ParagraphProperties(), StyleSheet.NIL_STYLE);
CharacterRun cr = p2.insertBefore("highlighted text\r");
cr.setHighlighted((byte) 0x06); // red; ICO
document.write([...]); // document goes to somewhere
} catch (IOException e) {
e.printStackTrace();
}
ICO is a color structure
IPAT is a list of predefined shading styles
We Only need to add these 3 lines to set the background color for Word documents by XWPF. We have to set these lines after declaring XWPFRun and it's text color:
CTShd cTShd = run.getCTR().addNewRPr().addNewShd();
cTShd.setVal(STShd.CLEAR);
cTShd.setFill(hex_background_color);

How to set heading style for a paragraph in a docx file using Apache POI? [duplicate]

This question already has answers here:
How can I use predefined formats in DOCX with POI?
(4 answers)
Closed 4 years ago.
I am trying to create a docx file with poi but I cannot set heading style for a paragraph.
XWPFDocument document= new XWPFDocument();
//Write the Document in file system
FileOutputStream out = new FileOutputStream(new File("C:/Users/2/Desktop/RequirementModelDocument.docx"));
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
paragraph.setAlignment(ParagraphAlignment.LEFT);
paragraph.setStyle("Heading1");
run.setText(reqLevel.getName());
run.setBold(true);
run.setFontFamily("Calibri Light (Headings)");
Its like ignores the paragraph.setStyle("Heading1"); line. I've looked at the apache's examples but I could not see any example about this issue.
If you start a new document, there are no styles defined. Either start from an existing template and copy the styles, or create your own (like I did, based on https://stackoverflow.com/a/27864752/461499 )
See here:
XWPFDocument document = new XWPFDocument();
XWPFStyles styles = document.createStyles();
String heading1 = "My Heading 1";
String heading2 = "My Heading 2";
String heading3 = "My Heading 3";
String heading4 = "My Heading 4";
addCustomHeadingStyle(document, styles, heading1, 1, 36, "4288BC");
addCustomHeadingStyle(document, styles, heading2, 2, 28, "4288BC");
addCustomHeadingStyle(document, styles, heading3, 3, 24, "4288BC");
addCustomHeadingStyle(document, styles, heading4, 4, 20, "000000");
XWPFParagraph paragraph = document.createParagraph();
paragraph.setStyle(heading1);
XWPFRun run = paragraph.createRun();
run.setText("Nice header!");
And
private static void addCustomHeadingStyle(XWPFDocument docxDocument, XWPFStyles styles, String strStyleId, int headingLevel, int pointSize, String hexColor) {
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);
CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
size.setVal(new BigInteger(String.valueOf(pointSize)));
CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
size2.setVal(new BigInteger("24"));
CTFonts fonts = CTFonts.Factory.newInstance();
fonts.setAscii("Loma" );
CTRPr rpr = CTRPr.Factory.newInstance();
rpr.setRFonts(fonts);
rpr.setSz(size);
rpr.setSzCs(size2);
CTColor color=CTColor.Factory.newInstance();
color.setVal(hexToBytes(hexColor));
rpr.setColor(color);
style.getCTStyle().setRPr(rpr);
// is a null op if already defined
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}
public static byte[] hexToBytes(String hexString) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
byte[] bytes = adapter.unmarshal(hexString);
return bytes;
}
I found a solution in the link below. Sorry for the duplication.
How can I use predefined formats in DOCX with POI?
But, If you have any other solution without using a template file, please let me know :)

Categories