• 向Docx4j生成的word文档中添加布局--第二部分


    原文标题:Adding layout to your Docx4j-generated word documents, part 2

    原文链接:http://blog.iprofs.nl/2012/11/19/adding-layout-to-your-docx4j-generated-word-documents-part-2/

    原文作者:lvdpal

    发表日期:2012年11月19日

    注:我没有再试着翻译代码中的注释,因为我觉得我水平实在有限,翻译过来的注释还不如看英文来地明白...


    在前面发表的两篇博客中,我写了一些关于在docx文档中创建表格添加图像和布局的内容。本篇博客中我将继续介绍一些文档布局相关的示例:

    更改默认样式

    几乎所有的客户都想要他们自己的风格。Word提供了一些默认的样式但它们不够好(注意一下我没有更改两个图像之间的文本,因此图像中的文本并不反映实际的风格):

    大多数客户会想改变这些风格,在应用了我们在本例中创建的风格之后,上面的word文档看起来会像这样:

    [java] view plain copy
     
    1. public class ChangingTheStyleSheet {  
    2.     private static WordprocessingMLPackage  wordMLPackage;  
    3.    
    4.     /** 
    5.      *  First we create the package, then we alter the style sheet and add some 
    6.      *  styled paragraphs. Finally we save the package. 
    7.      */  
    8.     public static void main (String[] args) throws Docx4JException {  
    9.         wordMLPackage = WordprocessingMLPackage.createPackage();  
    10.         alterStyleSheet();  
    11.    
    12.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title",  
    13.             "Hello World! This title is now in Arial.");  
    14.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Subtitle",  
    15.             "Subtitle, this subtitle is now Arial too");  
    16.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Heading1",  
    17.             "As is Heading1");  
    18.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Heading2",  
    19.             "Heading2 is now Arial, no longer bold and has an underline " +  
    20.             "and fontsize 12");  
    21.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Heading3",  
    22.             "Heading3 is now Arial");  
    23.         wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Normal",  
    24.             "And normal text has changed to Arial and fontsize 10");  
    25.    
    26.         wordMLPackage.save(new java.io.File("src/main/files/HelloWord12.docx") );  
    27.     }  
    28.    
    29.     /** 
    30.      *  This method alters the default style sheet that is part of each document. 
    31.      * 
    32.      *  To do this, we first retrieve the style sheet from the package and then 
    33.      *  get the Styles object from it. From this object, we get the list of actual 
    34.      *  styles and iterate over them. 
    35.      *  We check against all styles we want to alter and apply the alterations if 
    36.      *  applicable. 
    37.      * 
    38.      *  @param wordMLPackage 
    39.      */  
    40.     public static void alterStyleSheet() {  
    41.         StyleDefinitionsPart styleDefinitionsPart =  
    42.             wordMLPackage.getMainDocumentPart().getStyleDefinitionsPart();  
    43.         Styles styles = styleDefinitionsPart.getJaxbElement();  
    44.    
    45.         List<Style>  stylesList = styles.getStyle();  
    46.         for (Style style : stylesList) {  
    47.             if (style.getStyleId().equals("Normal")) {  
    48.                 alterNormalStyle(style);  
    49.             } else if (style.getStyleId().equals("Heading2")) {  
    50.                 alterHeading2Style(style);  
    51.             } else if (style.getStyleId().equals("Heading1") ||  
    52.                     style.getStyleId().equals("Heading3") ||  
    53.                     style.getStyleId().equals("Title") ||  
    54.                     style.getStyleId().equals("Subtitle")) {  
    55.                 getRunPropertiesAndRemoveThemeInfo(style);  
    56.             }  
    57.         }  
    58.     }  
    59.    
    60.     /** 
    61.      *  First we create a run properties object as we want to remove nearly all of 
    62.      *  the existing styling. Then we change the font and font size and set the 
    63.      *  run properties on the given style. As in previous examples, the font size 
    64.      *  is defined to be in half-point size. 
    65.      */  
    66.     private static void alterNormalStyle(Style style) {  
    67.         // we want to change (or remove) almost all the run properties of the  
    68.         // normal style, so we create a new one.  
    69.         RPr rpr = new RPr();  
    70.         changeFontToArial(rpr);  
    71.         changeFontSize(rpr, 20);  
    72.         style.setRPr(rpr);  
    73.     }  
    74.    
    75.     /** 
    76.      *  For this style, we get the existing run properties from the style and 
    77.      *  remove the theme font information from them. Then we also remove the bold 
    78.      *  styling, change the font size (half-points) and add an underline. 
    79.      */  
    80.     private static void alterHeading2Style(Style style) {  
    81.         RPr rpr = getRunPropertiesAndRemoveThemeInfo(style);  
    82.         removeBoldStyle(rpr);  
    83.         changeFontSize(rpr, 24);  
    84.         addUnderline(rpr);  
    85.     }  
    86.    
    87.     private static RPr getRunPropertiesAndRemoveThemeInfo(Style style) {  
    88.         // We only want to change some settings, so we get the existing run  
    89.         // properties from the style.  
    90.         RPr rpr = style.getRPr();  
    91.         removeThemeFontInformation(rpr);  
    92.         return rpr;  
    93.     }  
    94.    
    95.     /** 
    96.      *  Change the font of the given run properties to Arial. 
    97.      * 
    98.      *  A run font specifies the fonts which shall be used to display the contents 
    99.      *  of the run. Of the four possible types of content, we change the styling of 
    100.      *  two of them: ASCII and High ANSI. 
    101.      *  Finally we add the run font to the run properties. 
    102.      * 
    103.      *  @param runProperties 
    104.      */  
    105.     private static void changeFontToArial(RPr runProperties) {  
    106.         RFonts runFont = new RFonts();  
    107.         runFont.setAscii("Arial");  
    108.         runFont.setHAnsi("Arial");  
    109.         runProperties.setRFonts(runFont);  
    110.     }  
    111.    
    112.     /** 
    113.      * Change the font size of the given run properties to the given value. 
    114.      * 
    115.      * @param runProperties 
    116.      * @param fontSize  Twice the size needed, as it is specified as half-point value 
    117.      */  
    118.     private static void changeFontSize(RPr runProperties, int fontSize) {  
    119.         HpsMeasure size = new HpsMeasure();  
    120.         size.setVal(BigInteger.valueOf(fontSize));  
    121.         runProperties.setSz(size);  
    122.     }  
    123.    
    124.     /** 
    125.      * Removes the theme font information from the run properties. 
    126.      * If this is not removed then the styles based on the normal style won't 
    127.      * inherit the Arial font from the normal style. 
    128.      * 
    129.      * @param runProperties 
    130.      */  
    131.     private static void removeThemeFontInformation(RPr runProperties) {  
    132.         runProperties.getRFonts().setAsciiTheme(null);  
    133.         runProperties.getRFonts().setHAnsiTheme(null);  
    134.     }  
    135.    
    136.     /** 
    137.      * Removes the Bold styling from the run properties. 
    138.      * 
    139.      * @param runProperties 
    140.      */  
    141.     private static void removeBoldStyle(RPr runProperties) {  
    142.         runProperties.getB().setVal(false);  
    143.     }  
    144.    
    145.     /** 
    146.      * Adds a single underline to the run properties. 
    147.      * 
    148.      * @param runProperties 
    149.      */  
    150.     private static void addUnderline(RPr runProperties) {  
    151.         U underline = new U();  
    152.         underline.setVal(UnderlineEnumeration.SINGLE);  
    153.         runProperties.setU(underline );  
    154.     }  
    155. }  

    添加页脚或页眉

    添加页脚或页眉(或二者兼具)是一个很多客户都想要的特性。幸运的是,做这个并不是很难。这个例子是docx4j示例的一部分,但是我删掉了添加图像的部分只展示最基本的添加页脚部分。添加页眉,你需要做的仅仅是用header来替换footer(或者hdr替换ftr)。

    [java] view plain copy
     
    1. public class AddingAFooter {  
    2.     private static WordprocessingMLPackage wordMLPackage;  
    3.     private static ObjectFactory factory;  
    4.    
    5.     /** 
    6.      *  First we create the package and the factory. Then we create the footer part, 
    7.      *  which returns a relationship. This relationship is then used to create 
    8.      *  a reference. Finally we add some text to the document and save it. 
    9.      */  
    10.     public static void main (String[] args) throws Docx4JException {  
    11.         wordMLPackage = WordprocessingMLPackage.createPackage();  
    12.         factory = Context.getWmlObjectFactory();  
    13.    
    14.         Relationship relationship = createFooterPart();  
    15.         createFooterReference(relationship);  
    16.    
    17.         wordMLPackage.getMainDocumentPart().addParagraphOfText("Hello Word!");  
    18.    
    19.         wordMLPackage.save(new File("src/main/files/HelloWord14.docx") );  
    20.     }  
    21.    
    22.     /** 
    23.      *  This method creates a footer part and set the package on it. Then we add some 
    24.      *  text and add the footer part to the package. Finally we return the 
    25.      *  corresponding relationship. 
    26.      * 
    27.      *  @return 
    28.      *  @throws InvalidFormatException 
    29.      */  
    30.     private static Relationship createFooterPart() throws InvalidFormatException {  
    31.         FooterPart footerPart = new FooterPart();  
    32.         footerPart.setPackage(wordMLPackage);  
    33.    
    34.         footerPart.setJaxbElement(createFooter("Text"));  
    35.    
    36.         return wordMLPackage.getMainDocumentPart().addTargetPart(footerPart);  
    37.     }  
    38.    
    39.     /** 
    40.      *  First we create a footer, a paragraph, a run and a text. We add the given 
    41.      *  given content to the text and add that to the run. The run is then added to 
    42.      *  the paragraph, which is in turn added to the footer. Finally we return the 
    43.      *  footer. 
    44.      * 
    45.      *  @param content 
    46.      *  @return 
    47.      */  
    48.     private static Ftr createFooter(String content) {  
    49.         Ftr footer = factory.createFtr();  
    50.         P paragraph = factory.createP();  
    51.         R run = factory.createR();  
    52.         Text text = new Text();  
    53.         text.setValue(content);  
    54.         run.getContent().add(text);  
    55.         paragraph.getContent().add(run);  
    56.         footer.getContent().add(paragraph);  
    57.         return footer;  
    58.     }  
    59.    
    60.     /** 
    61.      *  First we retrieve the document sections from the package. As we want to add 
    62.      *  a footer, we get the last section and take the section properties from it. 
    63.      *  The section is always present, but it might not have properties, so we check 
    64.      *  if they exist to see if we should create them. If they need to be created, 
    65.      *  we do and add them to the main document part and the section. 
    66.      *  Then we create a reference to the footer, give it the id of the relationship, 
    67.      *  set the type to header/footer reference and add it to the collection of 
    68.      *  references to headers and footers in the section properties. 
    69.      * 
    70.      * @param relationship 
    71.      */  
    72.     private static void createFooterReference(Relationship relationship) {  
    73.         List<SectionWrapper> sections =  
    74.             wordMLPackage.getDocumentModel().getSections();  
    75.    
    76.         SectPr sectionProperties = sections.get(sections.size() - 1).getSectPr();  
    77.         // There is always a section wrapper, but it might not contain a sectPr  
    78.         if (sectionProperties==null ) {  
    79.             sectionProperties = factory.createSectPr();  
    80.             wordMLPackage.getMainDocumentPart().addObject(sectionProperties);  
    81.             sections.get(sections.size() - 1).setSectPr(sectionProperties);  
    82.         }  
    83.    
    84.         FooterReference footerReference = factory.createFooterReference();  
    85.         footerReference.setId(relationship.getId());  
    86.         footerReference.setType(HdrFtrRef.DEFAULT);  
    87.         sectionProperties.getEGHdrFtrReferences().add(footerReference);  
    88.     }  
    89. }  

    在页脚添加页码

    我在本博客要讨论的最后一个特性是怎样在我们刚创建的页脚处添加页码。你可能已经知道,在Word中页码是一个域,因此本例或多或少是前面的两个例子的结合:目录表和页脚。

    [java] view plain copy
     
    1. public class AddingPageNrToFooter {  
    2.     private static WordprocessingMLPackage wordMLPackage;  
    3.     private static ObjectFactory factory;  
    4.    
    5.     /** 
    6.      *  First we create the package and the factory. Then we create the footer. 
    7.      *  Finally we add two pages with text to the document and save it. 
    8.      */  
    9.     public static void main (String[] args) throws Exception {  
    10.         wordMLPackage = WordprocessingMLPackage.createPackage();  
    11.         factory = Context.getWmlObjectFactory();  
    12.    
    13.         Relationship relationship = createFooterPart();  
    14.         createFooterReference(relationship);  
    15.    
    16.         MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();  
    17.    
    18.         documentPart.addParagraphOfText("Hello World!");  
    19.    
    20.         addPageBreak(documentPart);  
    21.    
    22.         documentPart.addParagraphOfText("This is page 2!");  
    23.         wordMLPackage.save(new File("src/main/files/HelloWord15.docx") );  
    24.     }  
    25.    
    26.     /** 
    27.      *  As in the previous example, this method creates a footer part and adds it to 
    28.      *  the main document and then returns the corresponding relationship. 
    29.      * 
    30.      *  @return 
    31.      *  @throws InvalidFormatException 
    32.      */  
    33.     private static Relationship createFooterPart() throws InvalidFormatException {  
    34.         FooterPart footerPart = new FooterPart();  
    35.         footerPart.setPackage(wordMLPackage);  
    36.    
    37.         footerPart.setJaxbElement(createFooterWithPageNr());  
    38.    
    39.         return wordMLPackage.getMainDocumentPart().addTargetPart(footerPart);  
    40.     }  
    41.    
    42.     /** 
    43.      *  As in the previous example, we create a footer and a paragraph object. But 
    44.      *  this time, instead of adding text to a run, we add a field. And just as with 
    45.      *  the table of content, we have to add a begin and end character around the 
    46.      *  actual field with the page number. Finally we add the paragraph to the 
    47.      *  content of the footer and then return it. 
    48.      * 
    49.      * @return 
    50.      */  
    51.     public static Ftr createFooterWithPageNr() {  
    52.         Ftr ftr = factory.createFtr();  
    53.         P paragraph = factory.createP();  
    54.    
    55.         addFieldBegin(paragraph);  
    56.         addPageNumberField(paragraph);  
    57.         addFieldEnd(paragraph);  
    58.    
    59.         ftr.getContent().add(paragraph);  
    60.         return ftr;  
    61.     }  
    62.    
    63.     /** 
    64.      *  Creating the page number field is nearly the same as creating the field in 
    65.      *  the TOC example. The only difference is in the value. We use the PAGE 
    66.      *  command, which prints the number of the current page, together with the 
    67.      *  MERGEFORMAT switch, which indicates that the current formatting should be 
    68.      *  preserved when the field is updated. 
    69.      * 
    70.      * @param paragraph 
    71.      */  
    72.     private static void addPageNumberField(P paragraph) {  
    73.         R run = factory.createR();  
    74.         Text txt = new Text();  
    75.         txt.setSpace("preserve");  
    76.         txt.setValue(" PAGE   \* MERGEFORMAT ");  
    77.         run.getContent().add(factory.createRInstrText(txt));  
    78.         paragraph.getContent().add(run);  
    79.     }  
    80.    
    81.     /** 
    82.      * Every fields needs to be delimited by complex field characters. This method 
    83.      * adds the delimiter that precedes the actual field to the given paragraph. 
    84.      * @param paragraph 
    85.      */  
    86.     private static void addFieldBegin(P paragraph) {  
    87.         R run = factory.createR();  
    88.         FldChar fldchar = factory.createFldChar();  
    89.         fldchar.setFldCharType(STFldCharType.BEGIN);  
    90.         run.getContent().add(fldchar);  
    91.         paragraph.getContent().add(run);  
    92.     }  
    93.    
    94.     /** 
    95.      * Every fields needs to be delimited by complex field characters. This method 
    96.      * adds the delimiter that follows the actual field to the given paragraph. 
    97.      * @param paragraph 
    98.      */  
    99.     private static void addFieldEnd(P paragraph) {  
    100.         FldChar fldcharend = factory.createFldChar();  
    101.         fldcharend.setFldCharType(STFldCharType.END);  
    102.         R run3 = factory.createR();  
    103.         run3.getContent().add(fldcharend);  
    104.         paragraph.getContent().add(run3);  
    105.     }  
    106.    
    107.     /** 
    108.      * This method fetches the document final section properties, and adds a newly 
    109.      * created footer reference to them. 
    110.      * 
    111.      * @param relationship 
    112.      */  
    113.     public static void createFooterReference(Relationship relationship){  
    114.    
    115.         List<SectionWrapper> sections =  
    116.             wordMLPackage.getDocumentModel().getSections();  
    117.    
    118.         SectPr sectPr = sections.get(sections.size() - 1).getSectPr();  
    119.         // There is always a section wrapper, but it might not contain a sectPr  
    120.         if (sectPr==null ) {  
    121.             sectPr = factory.createSectPr();  
    122.             wordMLPackage.getMainDocumentPart().addObject(sectPr);  
    123.             sections.get(sections.size() - 1).setSectPr(sectPr);  
    124.         }  
    125.    
    126.         FooterReference footerReference = factory.createFooterReference();  
    127.         footerReference.setId(relationship.getId());  
    128.         footerReference.setType(HdrFtrRef.DEFAULT);  
    129.         sectPr.getEGHdrFtrReferences().add(footerReference);  
    130.     }  
    131.    
    132.     /** 
    133.      * Adds a page break to the document. 
    134.      * 
    135.      * @param documentPart 
    136.      */  
    137.     private static void addPageBreak(MainDocumentPart documentPart) {  
    138.         Br breakObj = new Br();  
    139.         breakObj.setType(STBrType.PAGE);  
    140.    
    141.         P paragraph = factory.createP();  
    142.         paragraph.getContent().add(breakObj);  
    143.         documentPart.getJaxbElement().getBody().getContent().add(paragraph);  
    144.     }  
    145. }  

    总结

    在三篇博客中,我展示了怎样创建一个word文档以及一些很常用的特性。这些示例全都是我的客户要求我需要创建的word文档。而且我觉得它们足以让你知道如何去做更多其它的事情,如果不是,用你所需要的特性创建一个文档并去查看内部的XML,如果一切仍然不能奏效,你可以到Docx4j论坛进行提问,docx4j的作者会定期尝试回答所有的问题。

    在以后的博客中我会展示一些关于xlsx文档的示例。

  • 相关阅读:
    pom.xml配置文件内容记录
    如何做出一个博客网站
    PHP中cookie和session的区别
    PHP链接mysql 出现:由于目标计算机积极拒绝,无法连接
    DOM增删操作(创建删除表格)
    DOM增删操作(select动态增加和删除以及清空)
    DOM增删改操作
    DOM操作表格
    SSD性能测试
    我的配置单
  • 原文地址:https://www.cnblogs.com/cxxjohnson/p/7899262.html
Copyright © 2020-2023  润新知