首页 文章

IText 使用 XML Worker 防止跨多个页面的行划分

提问于
浏览
9

我们正在使用带有 XML Worker 的 iText 5.5.7 并遇到了长表的问题,其中在页面末尾运行的行被分成两个到下一页(见图)。

我们已尝试按使用 iText,XMLWorker 防止文本块中的分页符iText 从 HTML 表格中删除 PDF 格式的页面中的建议使用page-break-inside:avoid;,但没有效果。

我们试过了

  • <tbody>中包装每一行并应用分页符避免(无效)

  • 定位tr, td并应用分页符(无效)

  • 将每个td的内容包装在div中并应用分页符(itext 一旦到达页面结尾就停止处理行)

我们的印象是支持page-break-inside:avoid,但尚未看到对此的确认。是否有使用 XML worker 创建此效果的示例或最佳实践,或者是执行此级别操作所需的 Java API?

干杯

目前正在分页的行:

行将溢出到下一页(参见红色轮廓)

期望的效果:包含太多数据的行包装到下一页
期望的结果,如果太长,行会突破到下一页(参见绿色轮廓)

1 回答

  • 8

    .NET 开发人员,但您应该能够轻松翻译以下 C#代码。

    任何时候默认的 XML Worker 实现都不能满足您的需求,您基本上只需要查看源代码。首先,查看XML Worker是否支持标签类中所需的标记。有一个很好的<table>实现支持page-break-inside:avoid样式,但它只能在<table>级别工作**,而不是行<tr>级别。幸运的是,覆盖End()方法并不是那么多。

    如果不支持标记,则需要通过继承AbstractTagProcessor来滚动自己的自定义标记处理器,但不是为了这个答案而去那里。

    无论如何,对代码。不是通过改变page-break-inside:avoid样式的行为来吹走默认实现,我们可以使用自定义HTML属性并充分利用两个世界:

    public class TableProcessor : Table
    {
        // custom HTML attribute to keep <tr> on same page if possible
        public const string NO_ROW_SPLIT = "no-row-split";
        public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
        {
            IList<IElement> result = base.End(ctx, tag, currentContent);
            var table = (PdfPTable)result[0];
    
            if (tag.Attributes.ContainsKey(NO_ROW_SPLIT))
            {
                // if not set,  table **may** be forwarded to next page
                table.KeepTogether = false;
                // next two properties keep <tr> together if possible
                table.SplitRows = true;
                table.SplitLate = true;
            }
            return new List<IElement>() { table };
        }
    }
    

    并且生成一些测试的简单方法HTML

    public string GetHtml()
    {
        var html = new StringBuilder();
        var repeatCount = 15;
        for (int i = 0; i < repeatCount; ++i) { html.Append("<h1>h1</h1>"); }
    
        var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vestibulum sollicitudin luctus. Curabitur at eros bibendum, porta risus a, luctus justo. Phasellus in libero vulputate, fermentum ante nec, mattis magna. Nunc viverra viverra sem, et pulvinar urna accumsan in. Quisque ultrices commodo mauris, et convallis magna. Duis consectetur nisi non ultrices dignissim. Aenean imperdiet consequat magna, ac ornare magna suscipit ac. Integer fermentum velit vitae porttitor vestibulum. Morbi iaculis sed massa nec ultricies. Aliquam efficitur finibus dolor, et vulputate turpis pretium vitae. In lobortis lacus diam, ut varius tellus varius sed. Integer pulvinar, massa quis feugiat pulvinar, tortor nisi bibendum libero, eu molestie est sapien quis odio. Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
    
        // default iTextSharp.tool.xml.html.table.Table (AbstractTagProcessor)
        // is at the <table>, **not <tr> level
        html.Append("<table style='page-break-inside:avoid;'>");
        html.AppendFormat(
            @"<tr><td style='border:1px solid #000;'>DEFAULT IMPLEMENTATION</td>
                <td style='border:1px solid #000;'>{0}</td></tr>",
            text
        );
        html.Append("</table>");
    
        // overriden implementation uses a custom HTML attribute to keep:
        // <tr> together - see TableProcessor
        html.AppendFormat("<table {0}>", TableProcessor.NO_ROW_SPLIT);
        for (int i = 0; i < repeatCount; ++i)
        {
            html.AppendFormat(
                @"<tr><td style='border:1px solid #000;'>{0}</td>
                <td style='border:1px solid #000;'>{1}</td></tr>",
                i, text
            );
        }
        html.Append("</table>");
        return html.ToString();
    }
    

    最后是解析代码:

    using (var stream = new FileStream(OUTPUT_FILE, FileMode.Create))
    {
        using (var document = new Document())
        {
            PdfWriter writer = PdfWriter.GetInstance(
                document, stream
            );
            document.Open();
    
            // instantiate custom tag processor and add to `HtmlPipelineContext`.
            var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
            tagProcessorFactory.AddProcessor(
                new TableProcessor(),
                new string[] { HTML.Tag.TABLE }
            );
            var htmlPipelineContext = new HtmlPipelineContext(null);
            htmlPipelineContext.SetTagFactory(tagProcessorFactory);
    
            var pdfWriterPipeline = new PdfWriterPipeline(document, writer);
            var htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline);
    
            var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);
            var cssResolverPipeline = new CssResolverPipeline(
                cssResolver, htmlPipeline
            );
    
            var worker = new XMLWorker(cssResolverPipeline, true);
            var parser = new XMLParser(worker);
            using (var stringReader = new StringReader(GetHtml()))
            {
                parser.Parse(stringReader);
            }
        }
    }
    

    完整来源.

    维护默认实现 - 首先将<table>保持在一起,而不是分成两页:

    在此输入图像描述

    自定义实现在第二个<table>中保持

    在此输入图像描述

相关问题