Reputation: 1023
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?
Upvotes: 2
Views: 2451
Reputation: 61945
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();
}
}
Upvotes: 1