我正在使用来自http://poi.apache.org/的“poi-bin-3.10.1-20140818”库
您可以复制.docx
文件循环中的所有段落doc.getParagraphs()
但Table
不是段落,所以Table
不是复制的。
要复制Table
,您必须获取IBodyElement
和循环doc.getBodyElements()
。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlException;
public class WordFinal {
public static void main(String[] args) throws IOException, XmlException {
XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
XWPFDocument destDoc = new XWPFDocument();
OutputStream out = new FileOutputStream("Destination.docx");
// ** This code will copy just one paragraph. **
XWPFParagraph pr = doc.getParagraphs().get(0);
destDoc.createParagraph();
int pos = destDoc.getParagraphs().size() - 1;
destDoc.setParagraph(pr, pos);
destDoc.write(out);
}
}
所以复制所有段落和表格的代码如下所示。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.xwpf.usermodel.BodyElementType;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.xmlbeans.XmlException;
public class WordFinal {
public static void main(String[] args) throws IOException, XmlException {
XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
XWPFDocument destDoc = new XWPFDocument();
OutputStream out = new FileOutputStream("Destination.docx");
for (IBodyElement bodyElement : doc.getBodyElements()) {
BodyElementType elementType = bodyElement.getElementType();
if (elementType.name().equals("PARAGRAPH")) {
XWPFParagraph pr = (XWPFParagraph) bodyElement;
destDoc.createParagraph();
int pos = destDoc.getParagraphs().size() - 1;
destDoc.setParagraph(pr, pos);
} else if( elementType.name().equals("TABLE") ) {
XWPFTable table = (XWPFTable) bodyElement;
destDoc.createTable();
int pos = destDoc.getTables().size() - 1;
destDoc.setTable(pos, table);
}
}
destDoc.write(out);
}
}
但即使通过这种方式,您也无法复制图像和样式。
所以复制的文件看起来与原始文件不同。
该org.apache.poi.xwpf.usermodel.XWPFRun.addPicture()
方法似乎有错误。
XWPFRun.addPicture()
Microsoft Word 无法打开包含添加的图像的 Docx 文档。
[参考] https://issues.apache.org/bugzilla/show_bug.cgi?id=49765
下面的代码包括下一个功能。
复制段落和表格的内容和样式
复制页面布局
从源 docx 文件复制图像
package com.overflow.heeseok;
import java.io.*;
import java.math.BigInteger;
import java.util.List;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STPageOrientation.Enum;
public class WordFinal {
public static void main(String[] args) throws IOException, XmlException
{
XWPFDocument srcDoc = new XWPFDocument(new FileInputStream("Source.docx"));
CustomXWPFDocument destDoc = new CustomXWPFDocument();
// Copy document layout.
copyLayout(srcDoc, destDoc);
OutputStream out = new FileOutputStream("Destination.docx");
for (IBodyElement bodyElement : srcDoc.getBodyElements()) {
BodyElementType elementType = bodyElement.getElementType();
if (elementType == BodyElementType.PARAGRAPH) {
XWPFParagraph srcPr = (XWPFParagraph) bodyElement;
copyStyle(srcDoc, destDoc, srcDoc.getStyles().getStyle(srcPr.getStyleID()));
boolean hasImage = false;
XWPFParagraph dstPr = destDoc.createParagraph();
// Extract image from source docx file and insert into destination docx file.
for (XWPFRun srcRun : srcPr.getRuns()) {
// You need next code when you want to call XWPFParagraph.removeRun().
dstPr.createRun();
if (srcRun.getEmbeddedPictures().size() > 0)
hasImage = true;
for (XWPFPicture pic : srcRun.getEmbeddedPictures()) {
byte[] img = pic.getPictureData().getData();
long cx = pic.getCTPicture().getSpPr().getXfrm().getExt().getCx();
long cy = pic.getCTPicture().getSpPr().getXfrm().getExt().getCy();
try {
// Working addPicture Code below...
String blipId = dstPr.getDocument().addPictureData(new ByteArrayInputStream(img),
Document.PICTURE_TYPE_PNG);
destDoc.createPictureCxCy(blipId, destDoc.getNextPicNameNumber(Document.PICTURE_TYPE_PNG),
cx, cy);
} catch (InvalidFormatException e1) {
e1.printStackTrace();
}
}
}
if (hasImage == false)
{
int pos = destDoc.getParagraphs().size() - 1;
destDoc.setParagraph(srcPr, pos);
}
} else if (elementType == BodyElementType.TABLE) {
XWPFTable table = (XWPFTable) bodyElement;
copyStyle(srcDoc, destDoc, srcDoc.getStyles().getStyle(table.getStyleID()));
destDoc.createTable();
int pos = destDoc.getTables().size() - 1;
destDoc.setTable(pos, table);
}
}
destDoc.write(out);
out.close();
}
// Copy Styles of Table and Paragraph.
private static void copyStyle(XWPFDocument srcDoc, XWPFDocument destDoc, XWPFStyle style)
{
if (destDoc == null || style == null)
return;
if (destDoc.getStyles() == null) {
destDoc.createStyles();
}
List<XWPFStyle> usedStyleList = srcDoc.getStyles().getUsedStyleList(style);
for (XWPFStyle xwpfStyle : usedStyleList) {
destDoc.getStyles().addStyle(xwpfStyle);
}
}
// Copy Page Layout.
//
// if next error message shows up, download "ooxml-schemas-1.1.jar" file and
// add it to classpath.
//
// [Error]
// The type org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageMar
// cannot be resolved.
// It is indirectly referenced from required .class files
//
// This error happens because there is no CTPageMar class in
// poi-ooxml-schemas-3.10.1-20140818.jar.
//
// [ref.] http://poi.apache.org/faq.html#faq-N10025
// [ref.] http://poi.apache.org/overview.html#components
//
// < ooxml-schemas 1.1 download >
// http://repo.maven.apache.org/maven2/org/apache/poi/ooxml-schemas/1.1/
//
private static void copyLayout(XWPFDocument srcDoc, XWPFDocument destDoc)
{
CTPageMar pgMar = srcDoc.getDocument().getBody().getSectPr().getPgMar();
BigInteger bottom = pgMar.getBottom();
BigInteger footer = pgMar.getFooter();
BigInteger gutter = pgMar.getGutter();
BigInteger header = pgMar.getHeader();
BigInteger left = pgMar.getLeft();
BigInteger right = pgMar.getRight();
BigInteger top = pgMar.getTop();
CTPageMar addNewPgMar = destDoc.getDocument().getBody().addNewSectPr().addNewPgMar();
addNewPgMar.setBottom(bottom);
addNewPgMar.setFooter(footer);
addNewPgMar.setGutter(gutter);
addNewPgMar.setHeader(header);
addNewPgMar.setLeft(left);
addNewPgMar.setRight(right);
addNewPgMar.setTop(top);
CTPageSz pgSzSrc = srcDoc.getDocument().getBody().getSectPr().getPgSz();
BigInteger code = pgSzSrc.getCode();
BigInteger h = pgSzSrc.getH();
Enum orient = pgSzSrc.getOrient();
BigInteger w = pgSzSrc.getW();
CTPageSz addNewPgSz = destDoc.getDocument().getBody().addNewSectPr().addNewPgSz();
addNewPgSz.setCode(code);
addNewPgSz.setH(h);
addNewPgSz.setOrient(orient);
addNewPgSz.setW(w);
}
}
和CustomXWPFDocument
类源。
package com.overflow.heeseok;
import java.io.IOException;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.xmlbeans.*;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
/**
* [ref] https://issues.apache.org/bugzilla/show_bug.cgi?id=49765
* [ref] http://pastebin.com/index/CbQ3iw8t, http://pastebin.com/2YAneYgt
*/
public class CustomXWPFDocument extends XWPFDocument
{
public CustomXWPFDocument() throws IOException
{
super();
}
public void createPictureCxCy(String blipId,int id, long cx, long cy)
{
CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();
String picXml = "" +
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
" <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:nvPicPr>" +
" <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
" <pic:cNvPicPr/>" +
" </pic:nvPicPr>" +
" <pic:blipFill>" +
" <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
" <a:stretch>" +
" <a:fillRect/>" +
" </a:stretch>" +
" </pic:blipFill>" +
" <pic:spPr>" +
" <a:xfrm>" +
" <a:off x=\"0\" y=\"0\"/>" +
" <a:ext cx=\"" + cx + "\" cy=\"" + cy + "\"/>" +
" </a:xfrm>" +
" <a:prstGeom prst=\"rect\">" +
" <a:avLst/>" +
" </a:prstGeom>" +
" </pic:spPr>" +
" </pic:pic>" +
" </a:graphicData>" +
"</a:graphic>";
//CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try
{
xmlToken = XmlToken.Factory.parse(picXml);
}
catch(XmlException xe)
{
xe.printStackTrace();
}
inline.set(xmlToken);
//graphicData.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(cx);
extent.setCy(cy);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("Picture " + id);
docPr.setDescr("Generated");
}
public void createPicture(String blipId,int id, int width, int height)
{
final int EMU = 9525;
width *= EMU;
height *= EMU;
//String blipId = getAllPictures().get(id).getPackageRelationship().getId();
createPictureCxCy(blipId, id, width, height);
}
}