How to copy a paragraph of .docx to another .docx with Java and retain the style

只愿长相守 提交于 2019-12-30 05:01:08

问题


I am trying to copy the content from a particular paragraph in a .docx to another empty .docx .the problem i have is that the style,bullets,numbering etc from the source.docx is not retained in the destination .docx.Here is my code

can anyone please tell me what are the changes to be added to the above code? Thanks in Advance!!

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"); 

        XWPFParagraph pr =doc.getParagraphs()[1];

        String copy=pr.getText();

        XWPFParagraph paragraphOne = destDoc.createParagraph(); 

        XWPFRun paragraphOneRunOne = paragraphOne.createRun();

        paragraphOneRunOne.setText(copy);

        destDoc.write(out);

         }
             }

回答1:


I'm using "poi-bin-3.10.1-20140818" library from http://poi.apache.org/

You can copy all paragraphs in the .docx file looping doc.getParagraphs().

But "Table" is not paragraph, so "Table" is not copied.

To copy "Table", you have to get IBodyElement and looping 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);

    }
}

So the code that copy all paragraphs and tables is like below.

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);
    }
}

But even through this way, you can't copy image and style.

So copied document looks different with original document.

It seems that org.apache.poi.xwpf.usermodel.XWPFRun.addPicture() method has bug.

Docx document including image added by XWPFRun.addPicture() is not opened by Microsoft Word.

[ref.] https://issues.apache.org/bugzilla/show_bug.cgi?id=49765

Below code is including next functionality.

1) copy contents and styles of paragraphs and tables

2) copy page layout

3) copy images from source docx file

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);
    }
}

And CustomXWPFDocument class source.

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);
    }
}


来源:https://stackoverflow.com/questions/10208097/how-to-copy-a-paragraph-of-docx-to-another-docx-with-java-and-retain-the-style

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!