Как редактировать документы MS Word с использованием Java?

1

У меня есть несколько шаблонов Word, и мое требование - заменить некоторые слова/места держателей в документе на основе ввода пользователя, используя Java. Я пробовал много библиотек, включая 2-3 версии docx4j но ничего не получилось, все они просто ничего не делали!

Я знаю, что этот вопрос задавали раньше, но я пробовал все варианты, которые я знаю. Итак, используя java-библиотеку, я могу "реально" заменить/редактировать эти шаблоны? Мои предпочтения относятся к библиотекам типов "простые в использовании/несколько строк".

Я использую Java 8 и мои шаблоны MS Word находятся в MS Word 2007.

Обновить

Этот код написан с использованием примера кода, предоставленного членом SO Joop Eggen

public Main() throws URISyntaxException, IOException, ParserConfigurationException, SAXException
    {
        URI docxUri = new URI("C:/Users/Yohan/Desktop/yohan.docx");
        Map<String, String> zipProperties = new HashMap<>();
        zipProperties.put("encoding", "UTF-8");

         FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties);

           Path documentXmlPath = zipFS.getPath("/word/document.xml");

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();

            Document doc = builder.parse(Files.newInputStream(documentXmlPath));

            byte[] content = Files.readAllBytes(documentXmlPath);
            String xml = new String(content, StandardCharsets.UTF_8);
            //xml = xml.replace("#DATE#", "2014-09-24");
            xml = xml.replace("#NAME#", StringEscapeUtils.escapeXml("Sniper"));

            content = xml.getBytes(StandardCharsets.UTF_8);
            Files.write(documentXmlPath, content);
    }

Однако это возвращает ошибку ниже

java.nio.file.ProviderNotFoundException: Provider "C" Not found

at: java.nio.file.FileSystems.newFileSystem(FileSystems.java:341) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:341)

at java.nio.fileFileSystems.newFileSystem(FileSystems.java:276)
  • 0
    может быть для рассмотрения (я бы пошел на Apache HWPF): stackoverflow.com/questions/203174/…
  • 0
    @CsBalazsHungary: ссылка создана 5 лет назад. Java 8 там не было в то время.
Показать ещё 6 комментариев
Теги:
ms-word
io

4 ответа

3

Попробуйте Apache POI. POI может работать с doc и docx, но docx более документирован, поэтому его лучше поддерживать.

UPD: вы можете использовать XDocReport, который использует POI. Также я рекомендую использовать xlsx для шаблонов, потому что он более подходит и документирован

  • 0
    Можете ли вы предоставить ссылку на пример, пожалуйста?
  • 0
    1) в свое время достаточно выборок из дистрибутива, читайте источники (POI и XDocReport) и гуглите.
Показать ещё 1 комментарий
2

Я потратил несколько дней на эту проблему, пока не обнаружил, что разница в том, что try-with-resources в экземпляре FileSystem появляются в Joop Eggen snippet, но не под вопросом:
try (FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties))
Без такого блока try-with-resources FileSystem не будет закрыт (как объясняется в учебнике Java), а документ документа не будет изменен.

2

Можно использовать для docx (zip с XML и другими файлами) файловую систему java zip и XML или обработку текста.

URI docxUri = ,,, // "jar:file:/C:/... .docx"
Map<String, String> zipProperties = new HashMap<>();
zipProperties.put("encoding", "UTF-8");
try (FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties)) {
    Path documentXmlPath = zipFS.getPath("/word/document.xml");

При использовании XML:

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();

    Document doc = builder.parse(Files.newInputStream(documentXmlPath));
    //Element root = doc.getDocumentElement();

Затем вы можете использовать XPath для поиска мест и записи XML снова.

Возможно даже, что вам не нужен XML, но он может заменить владельца места:

    byte[] content = Files.readAllBytes(documentXmlPath);
    String xml = new String(content, StandardCharsets.UTF_8);
    xml = xml.replace("#DATE#", "2014-09-24");
    xml = xml.replace("#NAME#", StringEscapeUtils.escapeXml("Sniper")));
    ...
    content = xml.getBytes(StandardCharsets.UTF_8);
    Files.delete(documentXmlPath);
    Files.write(documentXmlPath, content);

Для быстрой разработки переименуйте копию.docx в имя с расширением.zip файла и проверьте файлы.

File.write уже должен применять StandardOpenOption.TRUNCATE_EXISTING, но я добавил Files.delete когда Files.delete какая-то ошибка. См. Комментарии.

  • 0
    Спасибо за ответ. Вы хотите изменить расширение моего docx на .zip?
  • 0
    хм .. Может ли это работать со словом docx, включая изображения и таблицы?
Показать ещё 12 комментариев
0

Отступив немного, существует около 4 различных подходов для редактирования слов/заполнителей:

  • MERGEFIELD или DOCPROPERTY (если у вас возникают проблемы с этим в docx4j, то вы, вероятно, неправильно настроили свой входной docx)
  • привязка данных к контенту
  • переменная замена на поверхности документа (либо на уровне DOM/SAX, либо с использованием библиотеки)
  • делать вещи как XHTML, а затем импортировать

Перед тем, как выбрать один, вы должны решить, нужно ли также иметь возможность обрабатывать:

  • повторяющиеся данные (например, добавление строк таблицы)
  • условного содержания (например, целые абзацы, которые либо будут присутствовать, либо отсутствовать)
  • добавление изображений

Если вам это нужно, поля MERGEFIELD или DOCPROPERTY, вероятно, отсутствуют (хотя вы также можете использовать поля IF, если вы можете найти библиотеку, которая их поддерживает). И добавление изображений делает манипуляции DOM/SAX в соответствии с одним из других ответов, беспорядочным и подверженным ошибкам.

Другие вещи, которые следует учитывать:

  • ваши авторы: насколько они техничны? Что это значит для авторского интерфейса?
  • "пользовательский ввод", который вы упоминаете для замены переменных, является ли это данным или является частью этой проблемы, которую вы решаете?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню