简体   繁体   中英

How to change font size in style.xml for docx using apache poi

Right now I have a docx file that I loaded into XWPFDocument

XWPFDocument doc = new XWPFDocument(InputStream)

I can see it's current font size for different styles that's stored in style.xml by doing

for (CTStyle ctstyle : doc.getStyle().getStyleList())
{
    if (ctstyle.isSetRPr())
    {
        if (ctstyle.getRPr().isSetSz())
        {
            CTHpsMeasure size = ctstyle.getRPr().getSz();
            System.out.println(size.getVal());
        }
    }
}

I want to update the font size using poi, so I tried

for (CTStyle ctstyle : doc.getStyle().getStyleList())
{
    if (ctstyle.isSetRPr())
    {
        if (ctstyle.getRPr().isSetSz())
        {
            CTHpsMeasure size = ctstyle.getRPr().getSz();
            size.setVal(BigInteger.valueOf(12));
            ctstyle.getRPr().setSz(size);
        }
    }
}

However, after finish the above piece of code, if I check the font size of my document ( XWPFDocument doc object) using the first piece of code, the font size is still the original value, not the 12 I intended to set.

Is there any suggestions for how to fix this?

XWPFDocument.getStyle gets org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles but not the document part /word/styles.xml . So changings in this CTStyles will not be committed while writing out the XWPFDocument .

XWPFDocument.getStyles gets the XWPFStyles which extends POIXMLDocumentPart and overwrites commit method. So changings in this XWPFStyles will be committed while writing out the XWPFDocument .

Unfortunately there is not a method for getting all single style out of this XWPFStyles . There is a field private CTStyles ctStyles , which also is committed in protected void commit() , but not public accessible. So I have used reflection to get it.

From your previous questions I know that you have problems parsing a *.docx file which has font sizes wrongly set as doubles <w:sz w:val="24.0"/> which is definitely wrong and leads size.getVal() throwing org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException: Invalid integer value: 24.0 .

The ctstyle.getRPr().getSz() works without crash also having <w:sz w:val="24.0"/> . Here you could get the real meant size out of. For this do parsing the XML of the CTHpsMeasure size directly and then set the the value got from there truncated to BigInteger . BigDecimal provides a method for this.

And you additionally should also get and correct ctstyle.getRPr().getSzCs() , which is the size of the "Complex script" font used and also could be wrong.

The following works for me and after that all styles having font size have integer font size set. For example <w:sz w:val="24.0"/><w:szCs w:val="24.0"/> is <w:sz w:val="24"/><w:szCs w:val="24"/> then. Note the measurement unit here is half points 24 half points = 12 pt.

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure;

import java.math.BigInteger;
import java.math.BigDecimal;

import java.lang.reflect.Field;

public class WordChangeStyles {

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument(new FileInputStream("WordUsingStyles.docx"));

  XWPFStyles styles = document.getStyles(); //XWPFStyles extends POIXMLDocumentPart and overwrites commit method
  Field _ctStyles = XWPFStyles.class.getDeclaredField("ctStyles");
  _ctStyles.setAccessible(true); 
  CTStyles ctStyles = (CTStyles)_ctStyles.get(styles);

  CTHpsMeasure size;
  String sz;
  for (CTStyle ctstyle : ctStyles.getStyleList()) {
   if (ctstyle.isSetRPr()) {
    if (ctstyle.getRPr().isSetSz()) {
     size = ctstyle.getRPr().getSz();
     if (size != null) {
      sz = size.selectAttribute("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "val").newCursor().getTextValue();
      System.out.println(sz); //here you could get the real meant size out of
      size.setVal(new BigDecimal(sz).toBigInteger()); //sets the sz got from size truncated to BigInteger
      ctstyle.getRPr().setSz(size); //after that the font size should be integer

      System.out.println(ctstyle.getRPr().getSz().getVal());
     }

     size = ctstyle.getRPr().getSzCs();
     if (size != null) {
      sz = size.selectAttribute("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "val").newCursor().getTextValue();
      System.out.println(sz); //here you could get the real meant size out of
      size.setVal(new BigDecimal(sz).toBigInteger()); //sets the sz got from size truncated to BigInteger
      ctstyle.getRPr().setSzCs(size); //after that the font size should be integer

      System.out.println(ctstyle.getRPr().getSzCs().getVal());
     }
    }
   }
  } 

  document.write(new FileOutputStream("WordUsingStyles.docx")); //while writing out XWPFStyles will be committed
  document.close();
 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM