Reporting add-on, new lines on docx report

Hello Cuba platform community.

I am having the following issue with reporting to docx document. ‘\n’ or chr(10) characters automatically switches to spaces. I could not find how to solve this issue.

I am using SQL queries that return a string with possible new lines in it. But in docx report document new lines are shown as spaces.

Can anyone help with this problem?

Thanks in advance

Hi,

Unfortunately, the DOCX template doesn’t support the correct processing of \n char. We have an issue for the problem: Line end symbol '\n' is not considered in XlsxFormatter / DocxFormatter · Issue #20 · cuba-platform/reports · GitHub

Hi

Did this ever get resolved? I can see the issue and changes in github but it doesn’t look like the resolve was ever merged back into the main yarg and I don’t understand how to implement it by overriding the existing classes when it is embedded into the yarg jars.

Thanks
David

Hi David

Thanks for reminding.
We’ll come back to this issue, looks like there is a PR to merge.

Hi,

It’s possible to solve this problem by providing a custom content inliner. Inliner’s job is to replace a text which contains new line characters with a set of <t> and <br> elements in the resulting DOCX document.

You’ll need to create a new inliner in your project:

import com.haulmont.yarg.exception.ReportFormattingException;
import com.haulmont.yarg.formatters.impl.doc.OfficeComponent;
import com.haulmont.yarg.formatters.impl.inline.ContentInliner;
import com.sun.star.text.XText;
import com.sun.star.text.XTextRange;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.SpreadsheetMLPackage;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.SpreadsheetML.WorksheetPart;
import org.docx4j.wml.Br;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.R;
import org.docx4j.wml.Text;
import org.xlsx4j.sml.Cell;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Inliner splits the string value for lines and creates a pair of Text and Br elements for each line in text.
 */
public class ParagraphTextInliner implements ContentInliner {

    public final static String REGULAR_EXPRESSION = "\\$\\{paragraphText\\}";

    private Pattern tagPattern;

    public ParagraphTextInliner() {
        this.tagPattern = Pattern.compile(REGULAR_EXPRESSION, Pattern.CASE_INSENSITIVE);
    }

    @Override
    public Pattern getTagPattern() {
        return tagPattern;
    }

    @Override
    public void inlineToXlsx(SpreadsheetMLPackage pkg, WorksheetPart worksheetPart, Cell newCell, Object paramValue, Matcher matcher) {
        throw new UnsupportedOperationException("paragraphText format is not supported for XLSX");
    }

    @Override
    public void inlineToDoc(OfficeComponent officeComponent, XTextRange textRange, XText destination, Object paramValue, Matcher paramsMatcher) throws Exception {
        throw new UnsupportedOperationException("paragraphText format is not supported for DOC");
    }

    @Override
    public void inlineToDocx(WordprocessingMLPackage wordPackage, Text text, Object paramValue, Matcher paramsMatcher) {
        try {
            if (paramValue instanceof String) {
                String stringParamValue = (String) paramValue;
                ObjectFactory factory = Context.getWmlObjectFactory();
                String[] parts = stringParamValue.split("\n");
                R parent = (R) text.getParent();
                //spring text by \n and create a new <t> element followed by <br> for each part.
                for (String part : parts) {
                    Text textPart = factory.createText();
                    textPart.setValue(part);
                    parent.getContent().add(textPart);
                    Br br = factory.createBr();
                    parent.getContent().add(br);
                }
                text.setValue("");
            }
        } catch (Exception e) {
            throw new ReportFormattingException("An error occurred while inserting text with paragraphs to docx file", e);
        }
    }

    @Override
    public void inlineToXls(HSSFPatriarch patriarch, HSSFCell destination, Object paramValue, Matcher paramsMatcher) {
        throw new UnsupportedOperationException("paragraphText format is not supported for XLS");
    }
}

Create an inliners provider that registers this content inliner:

import com.haulmont.reports.libintegration.CubaInlinersProvider;

public class MyInlinersProvider extends CubaInlinersProvider {

    public MyInlinersProvider() {
        super();
        addInliner(new ParagraphTextInliner());
    }
}

In the spring.xml file register this inliners provider, it must replace the one provided by CUBA:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context">
     
    <!-- ... -->
    
    <bean id="reporting_lib_InlinersProvider"
          class="com.company.sample.core.inliner.MyInlinersProvider"/>
</beans>

In the report editor set the ${paragraphText} value format for required fields:

See the sample project: cuba-reports-paragraph-text.zip (103.1 KB)