2016-05-26 2 views
1

Я использую компоненты Apache POI XWPF и java для извлечения данных из XML-файла в документ Word. Пока все хорошо, но я изо всех сил пытаюсь создать оглавление. Я должен создать оглавление в начале метода, а затем обновить его в конце, чтобы получить все новые заголовки. В настоящее время я использую doc.createTOC(), где doc - это переменная, созданная из XWPFDocument, для создания таблицы в начале, а затем я использую doc.enforceUpdateFields() для обновления всего в конце документа. Но когда я открываю документ после запуска программы, оглавление пусто, но панель навигации содержит некоторые из указанных выше заголовков.Apache POI Содержание не обновляется

Комментарий, который рекомендуется включить в код. Поэтому я начал с создания документа из шаблона:

XWPFDocument doc = new XWPFDocument(new FileInputStream("D://Template.docx")); 

Я тогда создать оглавление:

doc.createTOC(); 

Затем в течение метода я добавлять заголовки документа:

XWPFParagraph documentControlHeading = doc.createParagraph(); 
documentControlHeading.setPageBreak(true); 
documentControlHeading.setAlignment(ParagraphAlignment.LEFT); 
documentControlHeading.setStyle("Tier1Header"); 

После добавления всех заголовков я хочу обновить документ, чтобы все новые заголовки отображались в оглавлении. Я это купить с помощью следующей команды:

doc.enforceUpdateFields(); 
+1

Дайте нам урезанную версию вашего кода, который показывает проблему, а может быть, кто-то может помочь. – jmarkmurphy

+0

Привет. Я добавил код в исходный вопрос, надеюсь, что это поможет. – Hendrien

ответ

0

Хммм ... Я смотрю на коде createTOC() метода, и кажется, что он ищет стили, которые выглядят как Heading #. Таким образом, Tier1Header не будет найден. Сначала попробуйте создать свой текст и используйте такие стили, как Heading 1 для ваших заголовков. Затем добавьте TOC, используя createTOC(). Он должен найти все заголовки при создании TOC. Я не знаю, влияет ли enforceUpdateFields() на TOC.

+0

Привет. Спасибо за ваш комментарий. Он работает, но TOC теперь находится в конце документа.Есть ли способ указать, где должен быть создан TOC? Функция enforceUpdateFields() работала для TOC, но она только обновляла его на панели навигации, а не в самом документе слова. – Hendrien

+0

Извините, не знаю ответа здесь, это в сорняках, и у меня нет времени, чтобы прорыть источник и найти его. Документы Word являются дополнительными в POI. И я не знаю, есть ли сейчас какие-либо коммиттеры, работающие над этим. HWPF даже не имеет возможности сделать ТОС. Было бы проще, если бы метод 'createToc()' возвращал TOC, чтобы вы могли добавлять строки самостоятельно, если это необходимо. Это не автоматическое, хотя. – jmarkmurphy

0

// Ваш шаблон docx должен содержать следующий или что-то подобное текст //, который будет искать и заменять WORD TOC.

// $ {TOC}

public static void main(String[] args) throws IOException, OpenXML4JException { 
     XWPFDocument docTemplate = null; 
     try { 
      File file = new File(PATH_TO_FILE); //"C:\\Reports\\Template.docx"; 
      FileInputStream fis = new FileInputStream(file); 
      docTemplate = new XWPFDocument(fis); 
      generateTOC(docTemplate); 
      saveDocument(docTemplate); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      if (docTemplate != null) { 
       docTemplate.close(); 
      } 
     } 
    } 

private static void saveDocument(XWPFDocument docTemplate) throws FileNotFoundException, IOException { 
    FileOutputStream outputFile = null; 
    try { 
     outputFile = new FileOutputStream(OUTFILENAME); 
     docTemplate.write(outputFile); 
    } finally { 
     if (outputFile != null) { 
      outputFile.close(); 
     } 
    } 
} 


public static void generateTOC(XWPFDocument document) throws InvalidFormatException, FileNotFoundException, IOException { 
     String findText = "${TOC}"; 
     String replaceText = ""; 
     for (XWPFParagraph p : document.getParagraphs()) { 
      for (XWPFRun r : p.getRuns()) { 
       int pos = r.getTextPosition(); 
       String text = r.getText(pos); 
       if (text != null && text.contains(findText)) { 
        text = text.replace(findText, replaceText); 
        r.setText(text, 0); 
        addField(p, "TOC \\o \"1-3\" \\h \\z \\u"); 
        break; 
       } 
      } 
     } 
    } 

private static void addField(XWPFParagraph paragraph, String fieldName) { 
    CTSimpleField ctSimpleField = paragraph.getCTP().addNewFldSimple(); 
    // ctSimpleField.setInstr(fieldName + " \\* MERGEFORMAT "); 
    ctSimpleField.setInstr(fieldName); 
    ctSimpleField.addNewR().addNewT().setStringValue("<<fieldName>>"); 
} 
+0

Обновление: добавьте следующую строку непосредственно перед методом сохранения: docTemplate.enforceUpdateFields(); – Programmer

0

Это код createTOC(), полученный путем проверки XWPFDocument.class:

public void createTOC() { 
    CTSdtBlock block = getDocument().getBody().addNewSdt(); 
    TOC toc = new TOC(block); 
    for (XWPFParagraph par : this.paragraphs) { 
     String parStyle = par.getStyle(); 
     if ((parStyle != null) && (parStyle.startsWith("Heading"))) try { 
      int level = Integer.valueOf(parStyle.substring("Heading".length())).intValue(); 
      toc.addRow(level, par.getText(), 1, "112723803"); 
     } catch (NumberFormatException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Как вы можете видеть, это добавляет к TOC все пункты, имеющие стили названный «HeadingX», причем X является числом. Но, к сожалению, этого недостаточно. Фактически этот метод прослушивается/не завершен в своей реализации.

Номер страницы, переданной в addRow(), всегда 1, он даже не рассчитан. Итак, в конце вы получите TOC со всеми вашими абзацами и конечными точками, дающими правильный отступ, но страницы будут всегда равны «1».


EDIT ... но, есть решение here.