2016-02-09 11 views
7

używamy itext 5.5.7 z XML Worker i napotkaliśmy problem z długimi tabelami, w których wiersze, które biegną od końca strony, są dzielone na dwie części na następną stronę (patrz zdjęcie).IText zapobiega łamaniu wierszy na wielu stronach przy użyciu XML Worker

Próbowaliśmy użyć page-break-inside:avoid; zgodnie z sugestiami w Prevent page break in text block with iText, XMLWorker i iText Cut between pages in PDF from HTML table, ale bez efektu.

staraliśmy

  • zawijania, każdy wiersz w <tbody> i stosując podziału strony ujemnych (brak efektu)
  • kierowania tr, td i stosując podział strony (brak efektu)
  • owijanie zawartość każdego td w div i stosowanie podziału strony (itext zatrzymuje przetwarzanie wierszy po dojściu do końca strony)

Jesteśmy pod wrażeniem page-break-inside:avoid jest obsługiwany, ale jeszcze nie widać potwierdzenia tego. Czy istnieje przykład lub najlepsza praktyka do tworzenia tego efektu za pomocą pracownika XML lub czy api aplikacji Java potrzebne do tego poziomu manipulacji?

okrzyki

Wiersze obecnie podziału między strony:

Rows are spilling on to the next page (see red outline)

Pożądany efekt: Wiersze zbyt dużo danych zawijać do następnej stronie Desired outcome, rows break to next page if too long (see green outline)

Odpowiedz

5

.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:

enter image description here

i wdrożenie zwyczaj utrzymuje wierszy razem w drugim <table>:

enter image description here

Powiązane problemy