我们正在使用带有XML Worker的iText 5.5.7,并且遇到了长表的问题,其中在页面末尾运行的行被分成两部分到下一页(见图)。
我们已尝试按照Prevent page break in text block with iText, XMLWorker和iText Cut between pages in PDF from HTML table中的建议使用page-break-inside:avoid;
但不起作用。
我们已经尝试了
<tbody>
中并应用分页符避免(无效)tr, td
并应用分页符(无效)td
的内容包装在div
中并应用分页符(一旦到达页面末尾,itext就停止处理行)我们的印象是page-break-inside:avoid
受到支持,但还没有看到对此的确认。是否有使用XML worker创建此效果的示例或最佳实践,或者是执行此级别操作所需的Java API?
欢呼声
目前正在分页的行:
答案 0 :(得分:8)
.NET开发人员,但您应该能够轻松翻译以下C#代码。
任何时候默认的XML Worker实现都不能满足您的需求,您基本上只需要查看源代码。首先,查看XML Worker
是否支持Tags class中所需的标记。对于支持<table>
样式的page-break-inside:avoid
,有一个很好的实现,但仅在<table>
级别,而不是行<tr>
级别。幸运的是,覆盖Table的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>
中将行保持在一起: