Apache POI: полностью удалить диаграмму из файла Word Template - PullRequest
0 голосов
/ 06 февраля 2020

Я использую шаблон Word с графиками Excel, которыми я хочу программно управлять с помощью библиотеки Java Apache POI. Для этого мне также нужно иметь возможность условно удалить диаграмму, которая хранится в этом шаблоне.

На основе сообщения Акселя Рихтерса ( Удаление диаграммы из слайда PowerPoint с помощью Apache POI ) Я думаю, что я почти на месте, но когда я хочу открыть обновленный файл Word, это выдает ошибку о нечитаемом контенте. Это то, что у меня есть до сих пор:

PackagePart packagePartChart = xWPFChart.getPackagePart();

PackagePart packagePartWordDoc = xWPFDocument.getPackagePart();
OPCPackage packageWordDoc = packagePartWordDoc.getPackage();

// iterate over all relations the chart has and remove them
for (PackageRelationship chartrelship : packagePartChart.getRelationships()) {
    String partname = chartrelship.getTargetURI().toString();
    PackagePart part = packageWordDoc.getPartsByName(Pattern.compile(partname)).get(0);
    packageWordDoc.removePart(part);
    packagePartChart.removeRelationship(chartrelship.getId());
}

// now remove the chart itself from the word doc                           
Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class); 
removeRelation.setAccessible(true); 
removeRelation.invoke(xWPFDocument, xWPFChart);

Если я разархивирую файл Word, я правильно вижу, что:

  1. связь между WordDo c и диаграммой будет удалена в '\ word \ _rels \ document. xml .rels'
  2. сама диаграмма удаляется в папке '\ word \ charts'
  3. отношения между документами, поддерживающими саму диаграмму, удалены в папке '\ word \ charts \' _rels
  4. и сами связанные элементы диаграммы удалены:
    • StyleN / ColorsN в папке '\ word \ charts' и
    • Microsoft_Excel_WorksheetN в папке '\ word \ embeddings'

Кто-нибудь знает, что здесь может пойти не так?

1 Ответ

0 голосов
/ 14 февраля 2020

Действительно, найти правильный абзац, содержащий диаграмму, было непросто. В конце для простоты я добавил таблицу-заполнитель из одной строки / одного столбца с одной ячейкой с текстом, скажем, «targetWordString» в ней, ПРЯМО перед диаграммой. С помощью приведенной ниже функции я определяю BodyElementID этой таблицы:

private Integer iBodyElementIterator (XWPFDocument wordDoc,String targetWordString) {
    Iterator<IBodyElement> iter = wordDoc.getBodyElementsIterator();
    Integer bodyElementID = null;
    while (iter.hasNext()) {
       IBodyElement elem = iter.next();
       bodyElementID = wordDoc.getBodyElements().indexOf(elem);
       if (elem instanceof XWPFParagraph) {

           XWPFParagraph paragraph = (XWPFParagraph) elem;
           for (XWPFRun runText : paragraph.getRuns()) {
                String text = runText.getText(0);                               
               Core.getLogger("WordExporter").trace("Body Element ID:  " + bodyElementID + " Text: " + text);
                if (text != null && text.equals(targetWordString)) {                        
                    break;                          
                }
            }

       } else if (elem instanceof XWPFTable) {
           if (((XWPFTable) elem).getRow(0) != null && ((XWPFTable) elem).getRow(0).getCell(0) != null) {
                // the first cell holds the name via the template
                String tableTitle = ((XWPFTable) elem).getRow(0).getCell(0).getText();
                if (tableTitle.equals(targetWordString)) {
                    break;
                }
                Core.getLogger("WordExporter").trace("Body Element ID:  " + bodyElementID + " Text: " + tableTitle);
           } else {
               Core.getLogger("WordExporter").trace("Body Element ID:  " + bodyElementID + " Table removed!");
           }

       }
       else {
           Core.getLogger("WordExporter").trace("Body Element ID:  " + bodyElementID + " Text: ?");
       }
    }
    return bodyElementID;
}

В основной части кода, которую я вызываю, эта функция определяет местонахождение таблицы, затем сначала удаляет диаграмму (ID +1) и затем таблица (ID)

int elementIDToBeRemoved = iBodyElementIterator(xWPFWordDoc,targetWordString);

xWPFWordDoc.removeBodyElement(elementIDToBeRemoved + 1);
xWPFWordDoc.removeBodyElement(elementIDToBeRemoved);

Она должна быть в таком порядке, потому что идентификаторы переупорядочиваются после того, как вы удалите промежуточное число, следовательно, сначала удалив таблицу, это будет означать, что диаграмма получит этот идентификатор в принципе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...