9

我们将 iText 5.5.7 与 XML Worker 一起使用,并且遇到了长表的问题,其中从页面末尾运行的行被分成两部分到下一页(见图)。

我们已尝试按照使用iText、XMLWorkeriText 在 HTML 表中的 PDF 页面之间剪切page-break-inside:avoid;防止文本块中的分页符中的建议使用,但没有效果。

我们已经尝试过

  • 将每一行包装在 a 中<tbody>并应用分页符避免(无效)
  • 定位tr, td和应用分页符(无效)
  • 将每个内容包装td在 a 中div并应用分页符(itext 一旦到达页面末尾就会停止处理行)

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

干杯

当前跨页面拆分的行:

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

期望的效果:数据过多的行换行到下一页 期望的结果,如果太长,行会中断到下一页(见绿色轮廓)

4

1 回答 1

9

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

每当默认的 XML Worker 实现不能满足您的需要时,您基本上都需要进行查看源代码的练习。首先,在Tags 类XML Worker中查看是否支持您想要的标签。有一个很好的实现支持该样式,但它只适用于级别,而不是行级别。幸运的是,重写Table的方法并没有太多工作。<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>保持在一起:

在此处输入图像描述

于 2017-01-11T06:31:23.157 回答