Add Custom XML Part using Apache POI

2019-08-12 17:03发布

问题:

What is the proper way to add custom XML Part to XLSX file using Apache POI?

I have tried creating package part and add relation to workbook using the code below, but my newly added part is added as blank file because the workbook clears package parts in POIXMLDocument#prepareForCommit().

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class AddCustomXmlPart {

    public static void main(String[] args) {
        String outputFileName = System.getProperty("user.home") + "/Documents/test-updated.xlsx";

        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            workbook.createSheet("Test");
            addCustomXmlPart(workbook);

            workbook.write(new FileOutputStream(outputFileName));

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        }
    }

    private static void addCustomXmlPart(XSSFWorkbook workbook) throws IOException, InvalidFormatException {
        final OPCPackage opcPackage = workbook.getPackage();
        final PackagePartName partName = PackagingURIHelper.createPartName("/customXml/item1.xml");
        final PackagePart part = opcPackage.createPart(partName, ContentTypes.PLAIN_OLD_XML);
        final OutputStream outputStream = part.getOutputStream();
        outputStream.write("<test>A</test>".getBytes());
        outputStream.close();

        final PackageRelationship packageRelationship = part.addRelationship(
                partName, TargetMode.INTERNAL, PackageRelationshipTypes.CUSTOM_XML);

        final POIXMLDocumentPart documentPart = new POIXMLDocumentPart(workbook, part, packageRelationship);
        workbook.addRelation(packageRelationship.getId(), documentPart);
    }
}

回答1:

As suggested by Gagravarr:

import java.io.*;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class AddCustomXmlUsingOpc {
    public static final String PARENT_PATH = System.getProperty("user.home") + "/Documents/";
    public static void main(String[] args) {

        String outputFileName1 = PARENT_PATH + "01.xlsx";
        String outputFileName2 = PARENT_PATH + "02.xlsx";

        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            workbook.createSheet("Test");
            workbook.write(new FileOutputStream(outputFileName1));

            final OPCPackage opcPackage = OPCPackage.open(new File(outputFileName1));
            addCustomXmlPart(opcPackage);
            opcPackage.save(new File(outputFileName2));

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        }
    }

    private static void addCustomXmlPart(OPCPackage opcPackage) throws IOException, InvalidFormatException {
        final PackagePartName partName = PackagingURIHelper.createPartName("/customXml/item1.xml");
        final PackagePart part = opcPackage.createPart(partName, ContentTypes.PLAIN_OLD_XML);
        final OutputStream outputStream = part.getOutputStream();
        outputStream.write("<test>A</test>".getBytes());
        outputStream.close();

        part.addRelationship(partName, TargetMode.INTERNAL, PackageRelationshipTypes.CUSTOM_XML);

        final PackagePartName workbookName = PackagingURIHelper.createPartName("/xl/workbook.xml");
        final PackagePart workbookPart = opcPackage.getPart(workbookName);
        workbookPart.addRelationship(partName, TargetMode.INTERNAL, PackageRelationshipTypes.CUSTOM_XML);
    }

}