如何通过poi为word中的不同部分设置页码 [英] how to set page number for different section in word by poi

查看:98
本文介绍了如何通过poi为word中的不同部分设置页码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的文档分为三部分:封面、内容和正文.我想为每个部分设置不同的页码.封面不需要页码.内容页码为罗马数字,正文页码为希腊数字.POI可以实现吗?

解决方案

Apache poi - 到目前为止 - 只有 abel 创建三种类型的页眉/页脚:HeaderFooterType.DEFAULT, .EVEN.First.

因此,为了满足您的要求,我们需要使用底层对象.我们需要作弊才能创建不同的页脚.

我们需要两个不同的页脚.一份用于您的第 2 部分(内容),另一份用于您的第 3 部分(文本).但两者都必须是 DEFAULT 类型.由于到目前为止使用 apache poi 是不可能的,我们首先为整个创建两个不同类型的不同页脚(FIRSTDEFAULT)文档.然后我们将 FIRST 页脚更改为 DEFAULT 并将其移动为第 2 部分的页脚参考.

示例:

import java.io.FileOutputStream;导入 org.apache.poi.xwpf.usermodel.*;导入 org.apache.poi.wp.usermodel.HeaderFooterType;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;公共类 CreateWordMultipleSectionPageNumbering {public static void main(String[] args) 抛出异常 {XWPFDocument 文档 = 新 XWPFDocument();//为第 2 节创建第一个页脚 - 首先创建为文档的第一个页脚XWPFFooter 页脚 = document.createFooter(HeaderFooterType.FIRST);//首先使其成为 HeaderFooterType.FIRST,以便以后能够再创建一个页脚//稍后将其更改为 HeaderFooterType.DEFAULTXWPFParagraph 段落 = footer.getParagraphArray(0);如果(段落==空)段落=footer.createParagraph();段落.setAlignment(ParagraphAlignment.CENTER);XWPFRun 运行 = 段落.createRun();run.setText("页面");段落.getCTP().addNewFldSimple().setInstr("PAGE \\* ROMAN MERGEFORMAT");运行 = 段落.createRun();run.setText(" of ");段落.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ROMAN MERGEFORMAT");//为第 3 部分 == 文档中的最后一部分创建第二个页脚页脚 = document.createFooter(HeaderFooterType.DEFAULT);段落 = 页脚.getParagraphArray(0);如果(段落==空)段落=footer.createParagraph();段落.setAlignment(ParagraphAlignment.CENTER);运行 = 段落.createRun();run.setText("页面");段落.getCTP().addNewFldSimple().setInstr("PAGE \\* ARABIC MERGEFORMAT");运行 = 段落.createRun();run.setText(" of ");段落.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ARABIC MERGEFORMAT");//创建文档内容.//第1节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("封面");//带有上面部分的部分设置的段落段落 = document.createParagraph();CTSectPr ctSectPr = 段落.getCTP().addNewPPr().addNewSectPr();//第2节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("内容");//带有上面部分的部分设置的段落段落 = document.createParagraph();CTSectPr ctSectPrSect2 = 段落.getCTP().addNewPPr().addNewSectPr();//我们稍后需要这个//第3节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("文本");//上面部分的部分设置==文档中的最后一部分CTDocument1 ctDocument = document.getDocument();CTBody ctBody = ctDocument.getBody();CTSectPr ctSectPrLastSect = ctBody.getSectPr();//由于上面的页脚设置,必须已经有一个SectPr//获取第一个页脚的页脚引用并将其移动为第 2 节的页脚引用CTHdrFtrRef ctHdrFtrRef = ctSectPrLastSect.getFooterReferenceArray(0);ctHdrFtrRef.setType(STHdrFtr.DEFAULT);//将此从 STHdrFtr.FIRST 更改为 STHdrFtr.DEFAULTCTHdrFtrRef[] ctHdrFtrRefs = 新的 CTHdrFtrRef[]{ctHdrFtrRef};ctSectPrSect2.setFooterReferenceArray(ctHdrFtrRefs);ctSectPrLastSect.removeFooterReference(0);//取消整个文档的有一个标题页",因为我们有一个标题部分(封面)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.

例如:如何设置罗马数字以 I II 开头,阿拉伯数字再次以 1,2 开头?"

如果在 Word 创建一个使用不同页码格式的 Word 文档.然后在 /word/document.xml 中你会发现类似:

<预><代码>...<w:sectPr>...<w:pgNumType w:start="1"/>...</w:sectPr>...

因此我们需要在 XML 中添加一个 PgNumType 元素.

再次完成示例:

import java.io.FileOutputStream;导入 org.apache.poi.xwpf.usermodel.*;导入 org.apache.poi.wp.usermodel.HeaderFooterType;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;导入 org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;公共类 CreateWordMultipleSectionPageNumbering {//页面大小和页面边框的默认部分设置//测量单位=缇(二十分之一英寸点)=1英寸=1440缇私有静态字符串 defaultSectPr ="<w:sectPr xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"+""//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) 抛出异常 {CTSectPr ctSectPrDefault = (CTPPr.Factory.parse(defaultSectPr)).getSectPr();XWPFDocument 文档 = 新 XWPFDocument();//设置页面大小和页面边框的默认部分设置CTDocument1 ctDocument = document.getDocument();CTBody ctBody = ctDocument.getBody();ctBody.setSectPr(ctSectPrDefault);//为第 2 节创建第一个页脚 - 首先创建为文档的第一个页脚XWPFFooter 页脚 = document.createFooter(HeaderFooterType.FIRST);//首先使其成为 HeaderFooterType.FIRST,以便以后能够再创建一个页脚//稍后将其更改为 HeaderFooterType.DEFAULTXWPFParagraph 段落 = footer.getParagraphArray(0);如果(段落==空)段落=footer.createParagraph();段落.setAlignment(ParagraphAlignment.CENTER);XWPFRun 运行 = 段落.createRun();run.setText("页面");段落.getCTP().addNewFldSimple().setInstr("PAGE \\* ROMAN MERGEFORMAT");运行 = 段落.createRun();run.setText(" of ");//paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ROMAN MERGEFORMAT");段落.getCTP().addNewFldSimple().setInstr("SECTIONPAGES \\* ROMAN MERGEFORMAT");//为第 3 节 == 文档中的最后一节创建第二个页脚页脚 = document.createFooter(HeaderFooterType.DEFAULT);段落 = 页脚.getParagraphArray(0);如果(段落==空)段落=footer.createParagraph();段落.setAlignment(ParagraphAlignment.CENTER);运行 = 段落.createRun();run.setText("页面");段落.getCTP().addNewFldSimple().setInstr("PAGE \\* ARABIC MERGEFORMAT");运行 = 段落.createRun();run.setText(" of ");//paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* ARABIC MERGEFORMAT");段落.getCTP().addNewFldSimple().setInstr("SECTIONPAGES \\* ARABIC MERGEFORMAT");//创建文档内容.//第1节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("封面");//带有上面部分的部分设置的段落段落 = document.createParagraph();段落.getCTP().addNewPPr().setSectPr(ctSectPrDefault);//第2节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("内容");段落 = document.createParagraph();运行 = 段落.createRun();run.setText("Lorem ipsum semit dolor ...");运行.addBreak(BreakType.PAGE);段落 = document.createParagraph();//带有上面部分的部分设置的段落段落 = document.createParagraph();段落.getCTP().addNewPPr().setSectPr(ctSectPrDefault);CTSectPr ctSectPrSect2 = 段落.getCTP().getPPr().getSectPr();//我们稍后需要这个//设置此页码再次从1开始ctSectPrSect2.addNewPgNumType().setStart(java.math.BigInteger.valueOf(1));//第3节段落 = document.createParagraph();运行=paragraph.createRun();run.setText("文本");段落 = document.createParagraph();运行 = 段落.createRun();run.setText("Lorem ipsum semit dolor ...");运行.addBreak(BreakType.PAGE);段落 = document.createParagraph();//上面部分的部分设置==文档中的最后一部分CTSectPr ctSectPrLastSect = ctBody.getSectPr();//由于上面的默认和页脚设置,必须已经有一个SectPr//设置此页码再次从1开始ctSectPrLastSect.addNewPgNumType().setStart(java.math.BigInteger.valueOf(1));//获取第一个页脚的页脚引用并将其移动为第 2 节的页脚引用CTHdrFtrRef ctHdrFtrRef = ctSectPrLastSect.getFooterReferenceArray(0);ctHdrFtrRef.setType(STHdrFtr.DEFAULT);//将此从 STHdrFtr.FIRST 更改为 STHdrFtr.DEFAULTCTHdrFtrRef[] ctHdrFtrRefs = 新的 CTHdrFtrRef[]{ctHdrFtrRef};ctSectPrSect2.setFooterReferenceArray(ctHdrFtrRefs);ctSectPrLastSect.removeFooterReference(0);//取消整个文档的有一个标题页",因为我们有一个标题部分(封面)ctSectPrLastSect.unsetTitlePg();document.write(new FileOutputStream("CreateWordMultipleSectionPageNumbering.docx"));}}

这也使用 Word 中的 SECTIONPAGES 字段代替 NUMPAGES 来仅对单个部分中的页面而不是整个文档页面进行编号.

它还使用默认的部分设置来设置每个部分的页面大小和页面边框.这与可以读取 *.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.

这篇关于如何通过poi为word中的不同部分设置页码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆