как установить номер страницы для другого раздела в слове по - PullRequest
0 голосов
/ 27 апреля 2018

Мой документ состоит из трех частей: обложка, содержание и текст. Я хочу установить разные номера страниц для каждого раздела. Обложка не нуждается в номерах страниц. Номера страниц содержания указаны римскими цифрами, а страницы в основном тексте - греческими цифрами. Можно ли это реализовать с помощью POI?

1 Ответ

0 голосов
/ 27 апреля 2018

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.

Например: «Как установить, чтобы римские цифры начинались с I II, а арабские цифры снова начинались с 1,2?»

Если в Word создать документ Word, который использует разные форматы нумерации страниц . Тогда в /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 файлы.

...