如何通过poi在word中为不同的部分设置页码
how to set page number for different section in word by poi
我的文档分为三部分:封面、内容和正文。我想为每个部分设置不同的页码。封面不需要页码。目录页码为罗马数字,正文页码为希腊数字。可以用POI实现吗?
Apache poi
是 - 直到现在 - 只有 abel 创建三种类型的页眉/页脚:HeaderFooterType.DEFAULT
、.EVEN
和 .First
.
因此,为了满足您的要求,我们需要使用底层低级对象。我们需要作弊才能创建不同的页脚。
我们需要两个不同的页脚。一份用于第 2 节(内容),一份用于第 3 节(正文)。但是两者都必须是 DEFAULT
类型。由于到目前为止使用 apache poi
是不可能的,我们首先为整个文档创建两个不同类型的页脚(FIRST
和 DEFAULT
)。然后我们将 FIRST
页脚更改为 DEFAULT
并将其移动为第 2 部分的页脚参考。
示例:
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"));
}
}
使用的低级对象参考:http://grepcode.com/snapshot/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/。
以上代码说明了原理。如果需要满足进一步的要求,那么应该知道 *.docx
文件只是一个 ZIP
存档,可以解压缩并查看它。因此,可以使用 Word
创建满足要求的 *.docx
文件,然后解压缩并查看 /word/document.xml
。
例如:
"How to set roman numerals start with I II and arabic numerals start with 1,2 again?"
如果在 Word
create a Word document that uses different page numbering formats 中。然后在 /word/document.xml
你会发现像这样的东西:
...
<w:sectPr>
...
<w:pgNumType w:start="1"/>
...
</w:sectPr>
...
因此我们需要在 XML
中添加一个 PgNumType
元素。
再次完成示例:
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"));
}
}
这也使用 Word
中的 SECTIONPAGES
字段代替 NUMPAGES
来仅对单个部分中的页面编号而不是整个文档页面。
它还对每个部分的页面大小和页面边框使用默认部分设置。这与可以读取 *.docx
个文件的不同文字处理应用程序更兼容。
我的文档分为三部分:封面、内容和正文。我想为每个部分设置不同的页码。封面不需要页码。目录页码为罗马数字,正文页码为希腊数字。可以用POI实现吗?
Apache poi
是 - 直到现在 - 只有 abel 创建三种类型的页眉/页脚:HeaderFooterType.DEFAULT
、.EVEN
和 .First
.
因此,为了满足您的要求,我们需要使用底层低级对象。我们需要作弊才能创建不同的页脚。
我们需要两个不同的页脚。一份用于第 2 节(内容),一份用于第 3 节(正文)。但是两者都必须是 DEFAULT
类型。由于到目前为止使用 apache poi
是不可能的,我们首先为整个文档创建两个不同类型的页脚(FIRST
和 DEFAULT
)。然后我们将 FIRST
页脚更改为 DEFAULT
并将其移动为第 2 部分的页脚参考。
示例:
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"));
}
}
使用的低级对象参考:http://grepcode.com/snapshot/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/。
以上代码说明了原理。如果需要满足进一步的要求,那么应该知道 *.docx
文件只是一个 ZIP
存档,可以解压缩并查看它。因此,可以使用 Word
创建满足要求的 *.docx
文件,然后解压缩并查看 /word/document.xml
。
例如: "How to set roman numerals start with I II and arabic numerals start with 1,2 again?"
如果在 Word
create a Word document that uses different page numbering formats 中。然后在 /word/document.xml
你会发现像这样的东西:
...
<w:sectPr>
...
<w:pgNumType w:start="1"/>
...
</w:sectPr>
...
因此我们需要在 XML
中添加一个 PgNumType
元素。
再次完成示例:
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"));
}
}
这也使用 Word
中的 SECTIONPAGES
字段代替 NUMPAGES
来仅对单个部分中的页面编号而不是整个文档页面。
它还对每个部分的页面大小和页面边框使用默认部分设置。这与可以读取 *.docx
个文件的不同文字处理应用程序更兼容。