I am trying to create a word document in which I will have no footer only in the first page and a footer for the rest of the pages. I wrote the following code (I also tried to change -reverse- the order of creation of footer and footerFirst objects) but that did not help. I still have the default footer on all pages.
How should I disable the footer from the first page? Thanks in advance.
private XWPFDocument initDocument(String FILE) throws Exception{
XWPFDocument document = new XWPFDocument();
XWPFHeaderFooterPolicy headerFooterPolicy = document.getHeaderFooterPolicy();
if (headerFooterPolicy == null) headerFooterPolicy = document.createHeaderFooterPolicy();
// create header start
XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
//XWPFParagraph paragraph = footer.createParagraph();
XWPFParagraph paragraph = footer.getParagraphArray(0);
if (paragraph == null)
paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
run.setFontSize(11);
run.setFontFamily("Times New Roman");
run.setText("Some company info in the footer");
XWPFFooter footerFirst = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.FIRST);
paragraph = footerFirst.getParagraphArray(0);
if (paragraph == null)
paragraph = footerFirst.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
run.setText(" ");
return document;
}
That there is a different header set for first page only, means not that this header will also be shown. In Word GUI there is a checkbox [x] Different First Page in Header & Footer Tools to achieve that.
And according Office Open XML Part 4 - Markup Language Reference there must a boolean XML element titlePg be set to determine that there is a title page present.
In old apache poi versions using XWPFHeaderFooterPolicy this XML element titlePg can only be set using underlying low level objects using document.getDocument().getBody().getSectPr().addNewTitlePg();.
But using current apache poi versions (since 3.16) there is no need using XWPFHeaderFooterPolicy directly. Now there is XWPFDocument.createHeader and XWPFDocument.createFooter using a HeaderFooterType. This sets titlePg flag in XML when HeaderFooterType.FIRST is used.
Complete example which sets and uses HeaderFooterType.FIRST and HeaderFooterType.DEFAULT:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
public class CreateWordFooters {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
// the body content
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("The Body... first page");
paragraph = document.createParagraph();
run=paragraph.createRun();
run.addBreak(BreakType.PAGE);
run.setText("The Body... second page");
// create first page footer
XWPFFooter footer = document.createFooter(HeaderFooterType.FIRST);
paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
run.setText("First page footer...");
// create default footer
footer = document.createFooter(HeaderFooterType.DEFAULT);
paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run = paragraph.createRun();
run.setText("Default footer...");
FileOutputStream out = new FileOutputStream("CreateWordFooters.docx");
document.write(out);
out.close();
document.close();
}
}
Related
I'm adding a picture in the header of a word document. It shows a frame for the image and says "the image cannot currently be display". If I add text to the header it show the text, and if I add the image in the document body, it also shows the image. So is getting the image and it show text on the header, but no the image.
I'm running out of checkings, can anyone advise with this please?
Thank you!
public static void createHeaderAndFotter(XWPFDocument document) throws IOException, BadElementException, InvalidFormatException {
XWPFHeaderFooterPolicy headerFooterPolicy = document.getHeaderFooterPolicy();
if (headerFooterPolicy == null) headerFooterPolicy = document.createHeaderFooterPolicy();
File image = new ClassPathResource("/static/images/NIAB_Header.bmp").getFile();
BufferedImage bimg1 = ImageIO.read(image);
int width = bimg1.getWidth();
int height = bimg1.getHeight();
String imageName= image.getName();
XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
XWPFParagraph paragraph = header.createParagraph();
// XWPFParagraph paragraph = document.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
run.addPicture(new FileInputStream(image), XWPFDocument.PICTURE_TYPE_PNG, imageName, Units.toEMU(width), Units.toEMU(height));
run.setText("HEADER");
}
If I remove the commment on this line and comment the one before, then it adds the image
XWPFParagraph paragraph = document.createParagraph();
I believe whether this works or not highly depends on apache poiversion used. There was multiple issues with pictures in header/footer in former apache poi versions.
The following is the most minimal working code using apache poi 4.0.1. It is recommend always using the latest stable version.:
Code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.util.Units;
public class CreateWordHeaderWithImage {
public static void main(String[] args) throws Exception {
XWPFDocument doc = new XWPFDocument();
// the body content
XWPFParagraph paragraph = doc.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("The Body...");
// create header
XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
// header's first paragraph
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
FileInputStream in = new FileInputStream("samplePict.jpeg");
run.addPicture(in, Document.PICTURE_TYPE_JPEG, "samplePict.jpeg", Units.toEMU(100), Units.toEMU(50));
in.close();
run.setText("HEADER");
FileOutputStream out = new FileOutputStream("CreateWordHeaderWithImage.docx");
doc.write(out);
doc.close();
out.close();
}
}
Result:
I'm trying to add some shapes and a logo-file into the header of my word docx document. Adding a picture works for me, but i didn't find any solution how to add a shape. can anyone help me?
String imgFile="logo.png";
XWPFDocument document = new XWPFDocument(new FileInputStream("myfile.docx"));
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document, sectPr);
XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
XWPFParagraph paragraph = header.getParagraphArray(0);
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
XWPFPicture picture = run.addPicture(new FileInputStream(imgFile), XWPFDocument.PICTURE_TYPE_PNG, imgFile, Units.toEMU(195), Units.toEMU(22));
String blipID = "";
for(XWPFPictureData picturedata : header.getAllPackagePictures()) {
blipID = header.getRelationId(picturedata);
}
picture.getCTPicture().getBlipFill().getBlip().setEmbed(blipID); //now they have a blipID too
At the end the header should look like this
thanks
Since the apache poi XWPF is really in beta state until now, such things are only possible if one knows exactly how Word will store it's contents into the XML. Then one can work around the inadequacies of apache poi XWPF. You have already used such a workaround which corrects the missed blipID when pictures are added to runs in header or footer.
To discover how Word will store it's contents into the XML is not rocket science. A *.docx file is simply a ZIP file. If one unzip this file using a Zip software, one can simply have a look into the XML files.
As far as I know adding shapes (in this case text boxes) in Word documents is not supported by apache poi directly. For this using the low level underlying objects (in this case CTGroupand CTShape) is needed.
Example: (code should be self explanatory)
import java.io.*;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTxbxContent;
import com.microsoft.schemas.vml.CTGroup;
import com.microsoft.schemas.vml.CTShape;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTabStop;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTabJc;
import org.w3c.dom.Node;
import java.math.BigInteger;
public class CreateWordHeaderFooterTextBoxPicture {
public static void main(String[] args) throws Exception {
XWPFDocument doc= new XWPFDocument();
// the body content
XWPFParagraph paragraph = doc.createParagraph();
XWPFRun run=paragraph.createRun();
run.setText("The Body:");
paragraph = doc.createParagraph();
run=paragraph.createRun();
run.setText("Lorem ipsum....");
// create header start
XWPFHeaderFooterPolicy headerFooterPolicy = doc.createHeaderFooterPolicy();
XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
// header's first paragraph
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);
// create tab stops
CTTabStop tabStop = paragraph.getCTP().getPPr().addNewTabs().addNewTab();
tabStop.setVal(STTabJc.CENTER);
int twipsPerInch = 1440;
tabStop.setPos(BigInteger.valueOf(3 * twipsPerInch));
tabStop = paragraph.getCTP().getPPr().getTabs().addNewTab();
tabStop.setVal(STTabJc.RIGHT);
twipsPerInch = 1440;
tabStop.setPos(BigInteger.valueOf(6 * twipsPerInch));
// first run in header's first paragraph, to be for first text box
run = paragraph.createRun();
// create inline text box in run
CTGroup ctGroup = CTGroup.Factory.newInstance();
CTShape ctShape = ctGroup.addNewShape();
ctShape.setStyle("width:80pt;height:24pt");
CTTxbxContent ctTxbxContent = ctShape.addNewTextbox().addNewTxbxContent();
XWPFParagraph textboxparagraph = new XWPFParagraph(ctTxbxContent.addNewP(), (IBody)header);
XWPFRun textboxrun = textboxparagraph.createRun();
textboxrun.setText("The TextBox 1...");
textboxrun.setFontSize(10);
Node ctGroupNode = ctGroup.getDomNode();
CTPicture ctPicture = CTPicture.Factory.parse(ctGroupNode);
CTR cTR = run.getCTR();
cTR.addNewPict();
cTR.setPictArray(0, ctPicture);
// add tab to run
run.addTab();
// second run in header's first paragraph, to be for logo picture
run = paragraph.createRun();
// add the picture in the headers run
String imgFile="Logo.png";
XWPFPicture picture = run.addPicture(new FileInputStream(imgFile), XWPFDocument.PICTURE_TYPE_PNG, imgFile, Units.toEMU(195), Units.toEMU(22));
String blipID = "";
for(XWPFPictureData picturedata : header.getAllPackagePictures()) {
blipID = header.getRelationId(picturedata);
}
picture.getCTPicture().getBlipFill().getBlip().setEmbed(blipID);
// add tab to run
run.addTab();
// third run in header's first paragraph, to be for second text box
run = paragraph.createRun();
// create inline text box in run
ctGroup = CTGroup.Factory.newInstance();
ctShape = ctGroup.addNewShape();
ctShape.setStyle("width:80pt;height:24pt");
ctTxbxContent = ctShape.addNewTextbox().addNewTxbxContent();
textboxparagraph = new XWPFParagraph(ctTxbxContent.addNewP(), (IBody)header);
textboxrun = textboxparagraph.createRun();
textboxrun.setText("The TextBox 2...");
textboxrun.setFontSize(10);
ctGroupNode = ctGroup.getDomNode();
ctPicture = CTPicture.Factory.parse(ctGroupNode);
cTR = run.getCTR();
cTR.addNewPict();
cTR.setPictArray(0, ctPicture);
// create header end
// create footer start
XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
run.setText("The Footer:");
doc.write(new FileOutputStream("test.docx"));
}
}
My document has three parts: cover, contents and text. I want to set different page number for each section. The cover does not need page numbers. The contents page numbers are in Rome numerals, and the pages in the main body are in Greek numbers. Can it be realized with POI?
Apache poi is - until now - only abel creating three types of header / footers: HeaderFooterType.DEFAULT, .EVEN and .First.
So for fulfilling your requirement we need using the underlaying low level objects. And we need cheating a little bit to be able creating different footers.
We need two different footers. One for your section 2 (contents) and one for your section 3 (text). But both must be of type DEFAULT. Since this is not possible using apache poi until now, we are first creating two different footers of different types (FIRST and DEFAULT) for the whole document. Then we change the FIRST footer to DEFAULT and move it to be footer reference for section 2.
Example:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;
public class CreateWordMultipleSectionPageNumbering {
public static void main(String[] args) throws Exception {
XWPFDocument document= new XWPFDocument();
//create first footer for section 2 - first created as first footer for the document
XWPFFooter footer = document.createFooter(HeaderFooterType.FIRST);
//making it HeaderFooterType.FIRST first to be able creating one more footer later
//will changing this later to HeaderFooterType.DEFAULT
XWPFParagraph paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
run.setText("Page ");
paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* ROMAN MERGEFORMAT");
run = paragraph.createRun();
run.setText(" of ");
paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ROMAN MERGEFORMAT");
//create second footer for section 3 == last section in document
footer = document.createFooter(HeaderFooterType.DEFAULT);
paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
run.setText("Page ");
paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* ARABIC MERGEFORMAT");
run = paragraph.createRun();
run.setText(" of ");
paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ARABIC MERGEFORMAT");
//create document content.
//section 1
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Cover");
//paragraph with section setting for section above
paragraph = document.createParagraph();
CTSectPr ctSectPr = paragraph.getCTP().addNewPPr().addNewSectPr();
//section 2
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Contents");
//paragraph with section setting for section above
paragraph = document.createParagraph();
CTSectPr ctSectPrSect2 = paragraph.getCTP().addNewPPr().addNewSectPr(); //we need this later
//section 3
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Text");
//section setting for section above == last section in document
CTDocument1 ctDocument = document.getDocument();
CTBody ctBody = ctDocument.getBody();
CTSectPr ctSectPrLastSect = ctBody.getSectPr(); //there must be a SectPr already because of the footer settings above
//get footer reference of first footer and move this to be footer reference for section 2
CTHdrFtrRef ctHdrFtrRef = ctSectPrLastSect.getFooterReferenceArray(0);
ctHdrFtrRef.setType(STHdrFtr.DEFAULT); //change this from STHdrFtr.FIRST to STHdrFtr.DEFAULT
CTHdrFtrRef[] ctHdrFtrRefs = new CTHdrFtrRef[]{ctHdrFtrRef};
ctSectPrSect2.setFooterReferenceArray(ctHdrFtrRefs);
ctSectPrLastSect.removeFooterReference(0);
//unset "there is a title page" for the whole document because we have a section for the title (cover)
ctSectPrLastSect.unsetTitlePg();
document.write(new FileOutputStream("CreateWordMultipleSectionPageNumbering.docx"));
}
}
Reference for used low level objects: http://grepcode.com/snapshot/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/.
The above code shows the principle. If the need is to fulfilling further requirements then one should know that a *.docx file is simply a ZIP archive which one can unzip and have a look into it. So one can using Word for creating a *.docx file which fulfils the requirements, then unzipping it and look at /word/document.xml.
For example:
"How to set roman numerals start with I II and arabic numerals start with 1,2 again?"
If in Word create a Word document that uses different page numbering formats . Then in /word/document.xml you will find something like:
...
<w:sectPr>
...
<w:pgNumType w:start="1"/>
...
</w:sectPr>
...
So we need a PgNumType element in the XML for this.
Complete example again:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;
public class CreateWordMultipleSectionPageNumbering {
//default section setting for page size and page borders
//measurement unit = twips (twentieth of an inch point) = 1 inch = 1440 twips
private static String defaultSectPr =
"<w:sectPr xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
+"<w:pgSz w:w=\"12240\" w:h=\"15840\"/>" //A4
+"<w:pgMar w:top=\"1417\" w:right=\"1417\" w:bottom=\"1134\" w:left=\"1417\""
+" w:header=\"720\" w:footer=\"720\" w:gutter=\"0\"/>"
+"<w:cols w:space=\"720\"/>"
+"</w:sectPr>";
public static void main(String[] args) throws Exception {
CTSectPr ctSectPrDefault = (CTPPr.Factory.parse(defaultSectPr)).getSectPr();
XWPFDocument document= new XWPFDocument();
//set the default section setting for page size and page borders
CTDocument1 ctDocument = document.getDocument();
CTBody ctBody = ctDocument.getBody();
ctBody.setSectPr(ctSectPrDefault);
//create first footer for section 2 - first created as first footer for the document
XWPFFooter footer = document.createFooter(HeaderFooterType.FIRST);
//making it HeaderFooterType.FIRST first to be able creating one more footer later
//will changing this later to HeaderFooterType.DEFAULT
XWPFParagraph paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
run.setText("Page ");
paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* ROMAN MERGEFORMAT");
run = paragraph.createRun();
run.setText(" of ");
//paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ROMAN MERGEFORMAT");
paragraph.getCTP().addNewFldSimple().setInstr("SECTIONPAGES \\* ROMAN MERGEFORMAT");
//create second footer for section 3 == last section in document
footer = document.createFooter(HeaderFooterType.DEFAULT);
paragraph = footer.getParagraphArray(0);
if (paragraph == null) paragraph = footer.createParagraph();
paragraph.setAlignment(ParagraphAlignment.CENTER);
run = paragraph.createRun();
run.setText("Page ");
paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* ARABIC MERGEFORMAT");
run = paragraph.createRun();
run.setText(" of ");
//paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ARABIC MERGEFORMAT");
paragraph.getCTP().addNewFldSimple().setInstr("SECTIONPAGES \\* ARABIC MERGEFORMAT");
//create document content.
//section 1
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Cover");
//paragraph with section setting for section above
paragraph = document.createParagraph();
paragraph.getCTP().addNewPPr().setSectPr(ctSectPrDefault);
//section 2
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Contents");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Lorem ipsum semit dolor ...");
run.addBreak(BreakType.PAGE);
paragraph = document.createParagraph();
//paragraph with section setting for section above
paragraph = document.createParagraph();
paragraph.getCTP().addNewPPr().setSectPr(ctSectPrDefault);
CTSectPr ctSectPrSect2 = paragraph.getCTP().getPPr().getSectPr(); //we need this later
//set this page numbering starting with 1 again
ctSectPrSect2.addNewPgNumType().setStart(java.math.BigInteger.valueOf(1));
//section 3
paragraph = document.createParagraph();
run=paragraph.createRun();
run.setText("Text");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Lorem ipsum semit dolor ...");
run.addBreak(BreakType.PAGE);
paragraph = document.createParagraph();
//section setting for section above == last section in document
CTSectPr ctSectPrLastSect = ctBody.getSectPr();
//there must be a SectPr already because of the default and footer settings above
//set this page numbering starting with 1 again
ctSectPrLastSect.addNewPgNumType().setStart(java.math.BigInteger.valueOf(1));
//get footer reference of first footer and move this to be footer reference for section 2
CTHdrFtrRef ctHdrFtrRef = ctSectPrLastSect.getFooterReferenceArray(0);
ctHdrFtrRef.setType(STHdrFtr.DEFAULT); //change this from STHdrFtr.FIRST to STHdrFtr.DEFAULT
CTHdrFtrRef[] ctHdrFtrRefs = new CTHdrFtrRef[]{ctHdrFtrRef};
ctSectPrSect2.setFooterReferenceArray(ctHdrFtrRefs);
ctSectPrLastSect.removeFooterReference(0);
//unset "there is a title page" for the whole document because we have a section for the title (cover)
ctSectPrLastSect.unsetTitlePg();
document.write(new FileOutputStream("CreateWordMultipleSectionPageNumbering.docx"));
}
}
This also uses SECTIONPAGES field in Word insteand of NUMPAGES to numbering only the pages in single section istead of the whole document pages.
Also it uses default section settings for page size and page borders in each section. This is more compatible with different word processing applications which can read *.docx files.
How do I create hyperlinks in Word documents using apache-poi? Is it possible to use relative paths?
There is XWPFHyperlinkRun but not a method for creating a such until now (March 2018, apache poi version 3.17). So we will need using underlaying low level methods.
The following example provides a method for creating a XWPFHyperlinkRun in a XWPFParagraph. After that the XWPFHyperlinkRun can be handled as a XWPFRun for further formatting since it extents this class.
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
public class CreateWordXWPFHyperlinkRun {
static XWPFHyperlinkRun createHyperlinkRun(XWPFParagraph paragraph, String uri) {
String rId = paragraph.getDocument().getPackagePart().addExternalRelationship(
uri,
XWPFRelation.HYPERLINK.getRelation()
).getId();
CTHyperlink cthyperLink=paragraph.getCTP().addNewHyperlink();
cthyperLink.setId(rId);
cthyperLink.addNewR();
return new XWPFHyperlinkRun(
cthyperLink,
cthyperLink.getRArray(0),
paragraph
);
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("This is a text paragraph having ");
XWPFHyperlinkRun hyperlinkrun = createHyperlinkRun(paragraph, "https://www.google.de");
hyperlinkrun.setText("a link to Google");
hyperlinkrun.setColor("0000FF");
hyperlinkrun.setUnderline(UnderlinePatterns.SINGLE);
run = paragraph.createRun();
run.setText(" in it.");
paragraph = document.createParagraph();
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("This is a text paragraph having ");
hyperlinkrun = createHyperlinkRun(paragraph, "./test.pdf"); //path in URI is relative to the Word document file
hyperlinkrun.setText("a link to a file");
hyperlinkrun.setColor("0000FF");
hyperlinkrun.setUnderline(UnderlinePatterns.SINGLE);
hyperlinkrun.setBold(true);
hyperlinkrun.setFontSize(20);
run = paragraph.createRun();
run.setText(" in it.");
FileOutputStream out = new FileOutputStream("CreateWordXWPFHyperlinkRun.docx");
document.write(out);
out.close();
document.close();
}
}
Update from 2021
Since POI 4.1.1 it is possible to add hyperlink run into paragraph using its method.
XWPFDocument docx = new XWPFDocument();
XWPFParagraph paragraph = docx.createParagraph();
run = paragraph.createHyperlinkRun("https://stackoverflow.com/");
run.setText("Stack Overflow");
run.setUnderline(UnderlinePatterns.SINGLE);
run.setColor("0000FF");
I have tried to set page orientation on single pages with help from here with no luck. This code snippet generates a document, but it only sets the last page to landscape. I can't figure out what is wrong... Any help or guidance would be appreciated!
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("FIRST PAGE");
changeOrientation(document, "landscape");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("SECOND PAGE");
changeOrientation(document, "portrait");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("THIRD PAGE");
changeOrientation(document, "landscape");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("FOURTH PAGE");
FileOutputStream fos = new FileOutputStream(new File("C:/test.docx"));
document.write(fos);
fos.close();
}
private static void changeOrientation(XWPFDocument document, String orientation){
CTDocument1 doc = document.getDocument();
CTBody body = doc.getBody();
CTSectPr section = body.addNewSectPr();
XWPFParagraph para = document.createParagraph();
CTP ctp = para.getCTP();
CTPPr br = ctp.addNewPPr();
br.setSectPr(section);
CTPageSz pageSize = section.isSetPgSz() ? section.getPgSz() : section.addNewPgSz();
if(orientation.equals("landscape")){
pageSize.setOrient(STPageOrientation.LANDSCAPE);
pageSize.setW(BigInteger.valueOf(842 * 20));
pageSize.setH(BigInteger.valueOf(595 * 20));
}
else{
pageSize.setOrient(STPageOrientation.PORTRAIT);
pageSize.setH(BigInteger.valueOf(842 * 20));
pageSize.setW(BigInteger.valueOf(595 * 20));
}
}
EDIT:
This give me the document.xml (which don't look right):
<?xml version="1.0" encoding="UTF-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body>
<w:p><w:r><w:t>FIRST PAGE</w:t></w:r></w:p>
<w:p><w:pPr><w:sectPr/></w:pPr></w:p>
<w:p><w:r><w:t>SECOND PAGE</w:t></w:r></w:p>
<w:p><w:pPr><w:sectPr/></w:pPr></w:p>
<w:p><w:r><w:t>THIRD PAGE</w:t></w:r></w:p>
<w:p><w:pPr><w:sectPr/></w:pPr></w:p>
<w:p><w:r><w:t>FOURTH PAGE</w:t></w:r></w:p>
<w:sectPr><w:pgSz w:orient="landscape" w:w="16840" w:h="11900"/></w:sectPr>
<w:sectPr><w:pgSz w:orient="portrait" w:h="16840" w:w="11900"/></w:sectPr>
<w:sectPr><w:pgSz w:orient="landscape" w:w="16840" w:h="11900"/></w:sectPr>
</w:body></w:document>
EDIT 2: This is how the document.xml looks like when created with Word (with some irrelevant stuff removed...). I'm afraid that I'm noot good enough at POI to figure out what to do to make it generate the xml like this instead:
<w:p w:rsidR="004E2FF4" w:rsidRDefault="004E2FF4"><w:pPr><w:sectPr w:rsidR="004E2FF4"><w:pgSz w:w="11906" w:h="16838"/></w:sectPr></w:pPr><w:r><w:t>FIRST PAGE</w:t></w:r></w:p>
<w:p w:rsidR="004E2FF4" w:rsidRDefault="004E2FF4"><w:pPr><w:sectPr w:rsidR="004E2FF4" w:rsidSect="004E2FF4"><w:pgSz w:w="16838" w:h="11906" w:orient="landscape"/></w:sectPr></w:pPr>
<w:r><w:lastRenderedPageBreak/><w:t>SECOND PAGE</w:t></w:r></w:p><w:p w:rsidR="004E2FF4" w:rsidRDefault="004E2FF4"><w:pPr><w:sectPr w:rsidR="004E2FF4"><w:pgSz w:w="11906" w:h="16838"/></w:sectPr></w:pPr>
<w:r><w:lastRenderedPageBreak/><w:t>THIRD PAGE</w:t></w:r></w:p><w:p w:rsidR="00D70BD0" w:rsidRDefault="004E2FF4">
<w:r><w:lastRenderedPageBreak/><w:t>FOURTH PAGE</w:t></w:r></w:p><w:sectPr w:rsidR="00D70BD0" w:rsidSect="004E2FF4"><w:pgSz w:w="16838" w:h="11906" w:orient="landscape"/></w:sectPr>
Edit 3:
Thanks for the nice guiding, but I can still not get it to work 100%. I have now changed the code to the following. But this resulting in setting the previous page orientation instead of the desired one. And the rest is not getting correct.
Image that shows the resulting pages
private static void changeOrientation(XWPFDocument document, String orientation, boolean pFinalSection){
CTSectPr section;
if (pFinalSection) {
CTDocument1 doc = document.getDocument();
CTBody body = doc.getBody();
section = body.getSectPr() != null ? body.getSectPr() : body.addNewSectPr();
XWPFParagraph para = document.createParagraph();
CTP ctp = para.getCTP();
CTPPr br = ctp.addNewPPr();
br.setSectPr(section);
} else {
XWPFParagraph para = document.createParagraph();
CTP ctp = para.getCTP();
CTPPr br = ctp.addNewPPr();
section = br.addNewSectPr();
br.setSectPr(section);
}
CTPageSz pageSize = section.isSetPgSz() ? section.getPgSz() : section.addNewPgSz();
if(orientation.equals("landscape")){
pageSize.setOrient(STPageOrientation.LANDSCAPE);
pageSize.setW(BigInteger.valueOf(842 * 20));
pageSize.setH(BigInteger.valueOf(595 * 20));
}
else{
pageSize.setOrient(STPageOrientation.PORTRAIT);
pageSize.setH(BigInteger.valueOf(842 * 20));
pageSize.setW(BigInteger.valueOf(595 * 20));
}
}
Please check my answer to the same problem in the post Landscape and portrait pages in the same word document using Apache POI XWPF in Java.
According to OOXML Specification ECMA-376, Fourth Edition, Part 1 - Fundamentals And Markup Language Reference - 17.6.18 sectPr (Section Properties), in a document with multiple sections, section properties (the sectPr element) are stored as the child element of :
the last paragraph in the section, for all sections except the final
section,
the body element, for the final section.
You can use addNewSectPr method of CTPPr to add a CTSectPr to it.
CTBody has a CTSectPr at end of it. You can get it using getSectPr method.