Как преобразовать HTML в правильно сформированный DOCX с неизменными атрибутами стиля - PullRequest
0 голосов
/ 17 февраля 2020

Я пытаюсь преобразовать файл HTML5 в docx, используя docx4j. Большая картина состоит в том, что HTML содержит данные Arabi c и данные Engli sh. Я установил стиль для элементов в моем HTML. Мой HTML выглядит аккуратно на chrome, но когда я конвертирую в docx с использованием docx4j, форматирование текста в арабском c теряется. На MS word, это показывает, что мой текст на арабском c имеет жирный набор стилей, но он не жирный. Точно так же направления RTL также потеряны. Таблицы меняются с RTL на LTR. В качестве обходного пути я использовал BufferedWriter для создания файла .do c, который соответствовал моему файлу HTML с атрибутами стиля, но в html присутствует изображение Base64, которого нет в .do c файл. Следовательно, необходимо конвертировать в формат .docx. Мое требование - редактируемый документ, сгенерированный из моего HTML. Пожалуйста, проведите меня, пока я чесал голову. Никакие исходные коды не работают.

Вот код, который я использую для преобразования HTML в docx.

public boolean convertHTMLToDocx(String inputFilePath, String outputFilePath, boolean headerFlag,
        boolean footerFlag,String orientation, String logoPath, String margin, JSONObject json,boolean isArabic) {
    boolean conversionFlag;
    boolean orientationFlag = false;
    try {
        if(!orientation.equalsIgnoreCase("Y")){
            orientationFlag = true;
        }
        String stringFromFile = FileUtils.readFileToString(new File(inputFilePath), "UTF-8");
        String unescaped = stringFromFile;
        WordprocessingMLPackage wordMLPackage  = WordprocessingMLPackage.createPackage();
        NumberingDefinitionsPart ndp = new NumberingDefinitionsPart();
        wordMLPackage.getMainDocumentPart().addTargetPart(ndp);
        ndp.unmarshalDefaultNumbering();

        ImportXHTMLProperties.setProperty("docx4j-ImportXHTML.Bidi.Heuristic", true);
        ImportXHTMLProperties.setProperty("docx4j-ImportXHTML.Element.Heading.MapToStyle", true);
        ImportXHTMLProperties.setProperty("docx4j-ImportXHTML.fonts.default.serif", "Frutiger LT Arabic 45 Light");
        ImportXHTMLProperties.setProperty("docx4j-ImportXHTML.fonts.default.sans-serif", "Frutiger LT Arabic 45 Light");
        ImportXHTMLProperties.setProperty("docx4j-ImportXHTML.fonts.default.monospace", "Frutiger LT Arabic 45 Light");

        XHTMLImporterImpl xHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
        xHTMLImporter.setHyperlinkStyle("Hyperlink");
        xHTMLImporter.setParagraphFormatting(FormattingOption.CLASS_PLUS_OTHER);
        xHTMLImporter.setTableFormatting(FormattingOption.CLASS_PLUS_OTHER);
        xHTMLImporter.setRunFormatting(FormattingOption.CLASS_PLUS_OTHER);

        wordMLPackage.getMainDocumentPart().getContent().addAll(xHTMLImporter.convert(unescaped, ""));

        XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(),true,true);
        File output = new File(outputFilePath);

        wordMLPackage.save(output);

        Console.log("file path where it is stored is" + " " + output.getAbsolutePath());
        if (headerFlag || footerFlag) {
            File file = new File(outputFilePath);
            InputStream in = new FileInputStream(file);

            wordMLPackage = WordprocessingMLPackage.load(in);
            if (headerFlag) {
                // set Header 
            }
            if (footerFlag) {
                // set Footer
            }

            wordMLPackage.save(file);
            Console.log("Finished editing the word document");
        }
        conversionFlag = true;
    } catch (InvalidFormatException e) {
        Error.log("Invalid format found:-" + getStackTrace(e));
        conversionFlag = false;
    } catch (Exception e) {
        Error.log("Error while converting:-" + getStackTrace(e));
        conversionFlag = false;
    }

    return conversionFlag;
}

1 Ответ

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

Начну с ответа, данного @JasonPlutext на один из подобных вопросов на форуме docx4j. Я должен упомянуть, что я использовал банки, у которых была эта проблема. Затем я перешел по ссылке ниже:

https://www.docx4java.org/forums/docx-java-f6/convert-html-to-docx-with-rtl-for-hebrew-arabic-language-t2712.html

и нашел баночки из приведенных ниже комментариев на указанной выше странице:

Вы можете попробуйте https://docx4java.org/docx4j/docx4j-Imp ... 180801.jar

Содержит https://github.com/plutext/docx4j-Impor ... f378022303

Не могли бы вы взглянуть на https://github.com/plutext/docx4j-Impor ... iTest. java и добавьте дополнительные тесты для смешанного иврита / арабского c и текста слева направо, особенно в тех случаях, когда вы считаете, что реализация не верна.

Кроме того, файлы jar не загружались, поэтому я произвел поиск по названию jar и загрузил их со всеми зависимостями с jardownload.com. Несмотря на то, что jars commons-code c и commons-io были 1.3, их необходимо обновить до последних jar-файлов для отображения изображения в формате docx после преобразования. Но, убедитесь, что html правильно сформирован, поскольку docx4j требует строгой приверженности правильно сформированному html.


Теперь я перейду к реальной части, т.е. как сохранить все так же, как html. Я преодолел его, используя простой байтовый массив, записываемый в файл .do c вместо .docx. Таким образом, do c будет выглядеть точно так же, как html. Единственная проблема, с которой я столкнулся, заключалась в том, что двоичные изображения не отображались. Вместо изображения появлялась только коробка. Итак, я написал два файла: первый, который считывает все мои двоичные теги изображений в файле html и использует декодер Base64 для декодирования изображений, сохраняет изображения на локальном диске на моем удаленном сервере и заменяет атрибут sr c всех такие теги img с новым местоположением на диске. (Новому местоположению предшествовал http: // {remote_server}: {remote_port} / {war_deployment_descriptor} / images /

2-й, я создал простой сервлет в моем файле war, развернутом на сервере, который слушал, чтобы получать запросы on / images и после получения запросов get с путевыми именами вернули изображение в outputtream. Вуаля, изображения начали поступать.


Вам решать, какое преобразование вы хотите сделать. .docx (который требуется преобразование с docx4j в качестве одного из параметров) или .do c (для этого нужно просто записать html в виде байтового массива в файл .do c и иметь 2 файла кода на месте). Мой совет для Engli sh документы go для преобразования .docx. Для арабского c или иврита или других языков RTL go для преобразования .do c, если не требуется строго генерировать .docx.


Listing the two files, please change as per your need:

File1.java
------------------------------------------------------------------------------------------

    public static void writeHTMLDatatoDoc(String content, String inputHTMLFile,String outputDocFile,String uniqueName) throws Exception {
        String baseTag = getRemoteServerURL()+"/{war_deployment_desciptor}/images?image=";
        String tag = "Image_";
        String ext = ".png";
        String srcTag = "";
        String pathOnServer = getDiskPath() + File.separator + "TemplateGeneration"
                + File.separator + "generatedTemplates" + File.separator + uniqueName + File.separator + "images" + File.separator;

        int i = 0;
        boolean binaryimgFlag = false;

        Pattern p = Pattern.compile("<img [^>]*src=[\\\"']([^\\\"^']*)");
        Matcher m = p.matcher(content);
        while (m.find()) {
            String src = m.group();
            int startIndex = src.indexOf("src=") + 5;
            int endIndex = src.length();

            // srcTag will contain data as data:image/png;base64,AAABAAEAEBAAAAEAGABoAw.........
            // Replace this whole later with path on local disk
            srcTag = src.substring(startIndex, src.length());

            if(srcTag.contains("base64")) {
                binaryimgFlag = true;
            }
            if(binaryimgFlag) {

                // Extract image mime type and image extension from srcTag containing binary image
                ext = extractMimeType(srcTag);
                if(ext.lastIndexOf(".") != -1 && ext.lastIndexOf(".") != 0)
                    ext = ext.substring(ext.lastIndexOf(".")+1);
                else 
                    ext = ".png";

                // read files already created for the different documents for this unique entity.
                // The location contains all image files as Image_{i}.{image_extension}
                // Sort files and read max counter in image names. 
                // Increase value of i to generate next image as Image_{incremented_i}.{image_entension}
                i = findiDynamicallyFromFilesCreatedForWI(pathOnServer);
                i++; // Increase count for next image

                // save whole data to replace later
                String srcTagBegin = srcTag; 

                // Remove data:image/png;base64, from srcTag , so I get only encoded image data.
                // Decode this using Base64 decoder.
                srcTag = srcTag.substring(srcTag.indexOf(",") + 1, srcTag.length());
                byte[] imageByteArray = decodeImage(srcTag);

                // Constrcu replacement tag
                String replacement = baseTag+pathOnServer+tag+i+ext;
                replacement = replacement.replace("\\", "/");

                // Writing image inside local directory on server
                FileOutputStream imageOutFile = new FileOutputStream(pathOnServer+tag+i+ext);
                imageOutFile.write(imageByteArray);
                content = content.replace(srcTagBegin, replacement);
                imageOutFile.close();
            }
        }

        //Re write HTML file
        writeHTMLData(content,inputHTMLFile);

        // write content to doc file
        writeHTMLData(content,outputDocFile);
    }

    public static int findiDynamicallyFromFilesCreatedForWI(String pathOnServer) {
        String path = pathOnServer;
        int nextFileCount = 0;
        String number = "";
        String[] dirListing = null;
        File dir = new File(path);
        dirListing = dir.list();
        if(dirListing.length != 0) {
            Arrays.sort(dirListing);
            int length = dirListing.length;
            int index = dirListing[length - 1].indexOf('.');
            number = dirListing[length - 1].substring(0,index);
            int index1 = number.indexOf('_');
            number = number.substring(index1+1,number.length());
            nextFileCount = Integer.parseInt(number);
        }
        return nextFileCount;
    }

    private static String extractMimeType(final String encoded) {
        final Pattern mime = Pattern.compile("^data:([a-zA-Z0-9]+/[a-zA-Z0-9]+).*,.*");
        final Matcher matcher = mime.matcher(encoded);
        if (!matcher.find())
            return "";
        return matcher.group(1).toLowerCase();
    }

    private static void writeHTMLData(String inputData, String outputFilepath) {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(outputFilepath)), Charset.forName("UTF-8")));
            writer.write(inputData);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(writer != null)
                    writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static byte[] decodeImage(String imageDataString) {
        return Base64.decodeBase64(imageDataString);
    }

    private static String readHTMLData(String inputFile) {
        String data = "";
        String str = "";

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(new File(inputFile)), StandardCharsets.UTF_8))) {
            while ((str = reader.readLine()) != null) {
                data += str;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

------------------------------------------------------------------------------------------

File2.java
------------------------------------------------------------------------------------------

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.newgen.clos.logging.consoleLogger.Console;
public class ImageServlet extends HttpServlet {
    public void init() throws ServletException {
    public ImageServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String param = request.getParameter("image");
        Console.log("Image Servlet executed");
        Console.log("File Name Requested: " + param);
        param.replace("\"", "");
        param.replace("%20"," ");
        File file = new File(param);
        response.setHeader("Content-Type", getServletContext().getMimeType(param));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + param + "\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }
}
------------------------------------------------------------------------------------------
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...