Apache poi
到目前为止,只有 abel 创建了三种类型的页眉/页脚:页眉页脚类型 http://poi.apache.org/apidocs/org/apache/poi/wp/usermodel/HeaderFooterType.html.DEFAULT
, .EVEN
and .First
.
因此,为了满足您的要求,我们需要使用底层的低级对象。我们需要稍微作弊才能创建不同的页脚。
我们需要两个不同的页脚。一份用于第 2 部分(内容),一份用于第 3 部分(文本)。但两者都必须是类型DEFAULT
。由于这是不可能使用apache poi
到目前为止,我们首先创建两个不同类型的不同页脚(FIRST
and DEFAULT
)对于整个文档。然后我们改变FIRST
页脚至DEFAULT
并将其移至第 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"));
}
}
使用的低级对象参考:http://grepcode.com/snapshot/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/ 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开头?”
If in Word
创建使用不同页码格式的 Word 文档 https://support.microsoft.com/en-us/help/326536/how-to-create-a-word-document-that-uses-different-page-numbering-forma。然后在/word/document.xml
你会发现类似的东西:
...
<w:sectPr>
...
<w:pgNumType w:start="1"/>
...
</w:sectPr>
...
所以我们需要一个PgNumType
中的元素XML
为了这。
再次完成示例:
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"));
}
}
这也使用SECTIONPAGES
领域在Word
代替NUMPAGES
仅对单个部分中的页面而不是整个文档页面进行编号。
它还使用每个部分中页面大小和页面边框的默认部分设置。这与可以读取的不同文字处理应用程序更加兼容*.docx
files.