如何将docx4j的WordprocessingMLPackage转为XWPFDocument统计文档页数行数
Great question! I totally get that switching your entire codebase from docx4j to Apache POI would be a huge hassle—let’s break down how to bridge the two libraries so you can get those page and line counts without a full rewrite.
The core idea here is that both libraries work with the underlying Office Open XML (OOXML) format, so we can serialize the docx4j document to a stream and then load that stream into an XWPFDocument. Here's a straightforward implementation:
import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.apache.poi.xwpf.usermodel.XWPFDocument; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class Docx4jToPoiHelper { public static XWPFDocument convertToXWPF(WordprocessingMLPackage wmlPackage) throws IOException { // Serialize the docx4j document to a byte stream ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); wmlPackage.save(outputStream); // Convert the byte stream to an input stream for POI ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); // Load the stream into XWPFDocument return new XWPFDocument(inputStream); } }
This approach works for most cases, though keep in mind it involves serializing the entire document—for very large files, you might want to test performance, but it’s perfectly acceptable for counting lines/pages.
Once you have the XWPFDocument, you can iterate through its paragraphs to count lines. Note that line breaks within a paragraph vs. new paragraphs might need different handling, but here’s a basic implementation:
// After converting to XWPFDocument XWPFDocument poiDoc = Docx4jToPoiHelper.convertToXWPF(yourWmlPackage); int totalLines = 0; for (XWPFParagraph paragraph : poiDoc.getParagraphs()) { String paraText = paragraph.getText(); if (paraText != null && !paraText.isBlank()) { // Split on line breaks (handles both Windows and Unix line endings) totalLines += paraText.split("\\r?\\n").length; } } System.out.println("Total line count: " + totalLines);
If you need to account for soft line breaks (those inserted via Shift+Enter in Word), you’ll want to check the paragraph’s runs for <w:br> elements, but the above code covers most common cases.
Here’s an important caveat: Apache POI does not provide a way to get accurate page counts directly from XWPFDocument. Word calculates pages dynamically during rendering, based on factors like paper size, margins, font sizes, and paragraph spacing—none of which are fully captured in the raw OOXML content.
Instead of converting to POI for page counts, you can use docx4j directly with its layout engine (you’ll need the docx4j-export-fo dependency). Here’s how:
import org.docx4j.convert.out.FOSettings; import org.docx4j.fonts.IdentityPlusMapper; import org.docx4j.fonts.Mapper; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.convert.out.fo.renderers.RendererApacheFOP; public class Docx4jPageCounter { public static int getAccuratePageCount(WordprocessingMLPackage wmlPackage) throws Exception { FOSettings foSettings = org.docx4j.Docx4J.createFOSettings(); Mapper fontMapper = new IdentityPlusMapper(); foSettings.setFontMapper(fontMapper); // Configure to calculate layout without generating output foSettings.setApacheFopMime("application/pdf"); RendererApacheFOP renderer = new RendererApacheFOP(foSettings); renderer.setWmlPackage(wmlPackage); // Trigger layout calculation renderer.layout(); return renderer.getPageCount(); } }
This gives you accurate page counts without needing to switch to POI at all—perfect since you’re already using docx4j.
内容的提问来源于stack exchange,提问作者Cold_Class

