.NET Developer ale powinieneś być w stanie z łatwością przetłumaczyć poniższy kod C#.
Za każdym razem, gdy domyślna implementacja modułu XML Worker nie spełnia Twoich wymagań, w zasadzie pozostaje ci ćwiczenie w przeglądaniu kodu źródłowego. Najpierw sprawdź, czy XML Worker
obsługuje wybrany znacznik w numerze Tags class. Istnieje przyjemna implementacja dla <table>
, która obsługuje styl page-break-inside:avoid
, ale działa tylko na poziomie tylko na poziomie na poziomie, a nie na poziomie <tr>
. Na szczęście to nie jest tak dużo pracy, aby przesłonić metodę End()
dla.
Jeśli tag jest nie obsługiwany, musisz przetoczyć własny procesor tagów, dziedzicząc po AbstractTagProcessor, ale nie będzie tam tej odpowiedzi.
W każdym razie, do kodu.Zamiast wieje od domyślna implementacja poprzez zmianę zachowania stylu page-break-inside:avoid
, możemy użyć niestandardowego HTML
atrybut i mieć najlepsze z obu światów:
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 };
}
}
i prosty sposób wygenerować kilka testów 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();
}
Wreszcie kod parsowanie:
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);
}
}
}
Full source.
Domyślna implementacja jest utrzymywana - pierwszy <table>
jest trzymane razem zamiast być podzielone na dwie strony:
i wdrożenie zwyczaj utrzymuje wierszy razem w drugim <table>
: