python-pdfkit(wkhtmltopdf) Overflow del sommario



wkhtmltoimage windows download (1)

Revisione del codice

Ho fatto una rapida revisione del codice nel tuo file XSL (e CSS). Anche se non risolve il tuo problema, aiuta a riprodurlo e capirlo. Ecco i miei commenti:

  • Il tuo XSL ha un refuso: <! begin LI> <! begin LI> non è una scheda XML valida. È un commento?

  • Preferisco usare la funzione concat() XPath per aggiungere direttamente i caratteri. Perché, se rientri il codice, puoi introdurre spazi bianchi extra.

    Quindi, ho sostituito:

    <xsl:attribute name="href"><xsl:value-of select="@link"/> . </xsl:attribute>

    Di:

    <xsl:attribute name="href">
      <xsl:value-of select="concat(@link, ' . ')"/>
    </xsl:attribute>
  • Ho aggiunto una xs:if per evitare di generare un <ul> vuoto se non è necessario:

    <xsl:if test="count(outline:item)">
      <ul>
        <xsl:comment>added to prevent self-closing tags in QtXmlPatterns</xsl:comment>
        <xsl:apply-templates select="outline:item"/>
      </ul>
    </xsl:if>
  • Ho anche corretto le voci CSS duplicate o mal formate, ho sostituito:

    li {
      border-bottom: 1px dashed rgb(45, 117, 183);
    }
    
    span {
      float: right;
    }
    
    li {
      list-style: none;
      margin-top: 30px;
    }
    
    ul ul {font-size: 80%; padding-top:0px;}
    ul {padding-left: 0em; padding-top:0px;}
    ul ul {padding-left: 1em; padding-top:0px;}
    a {text-decoration:none; color: color:#2d75b7;}

    di:

    span {
      float: right;
    }
    
    li {
      list-style: none;
      margin-top: 30px;
      border-bottom: 1px dashed rgb(45, 117, 183);
    }
    
    ul {
        font-size: 70px;
        font-family: arial;
        color: #2d75b7;
    }
    
    ul ul {
        font-size: 80%;
        padding-left: 1em;
        padding-top: 0px;
    }
    
    a {
        text-decoration: none;
        color: #2d75b7;
    }
    
  • Se scegli come target XHTML, il tag <style> ha un attributo type obbligatorio. Stessa osservazione per l'attributo <script> .

    <style type="text/css">...</style>
    <script type="text/javascript">...</script>

Riprodurre il problema

È stato un po 'difficile riprodurre il bug, a causa della mancanza di informazioni. Quindi immagino.

Per prima cosa creo un file TOC di esempio, che assomiglia a questo:

outline.xml

<?xml version="1.0" encoding="UTF-8"?>
<outline xmlns="http://wkhtmltopdf.org/outline">
  <item>
    <item title="Lorem ipsum dolor sit amet, consectetur adipiscing elit." page="2"/>
    <item title="Cras at odio ultrices, elementum leo at, facilisis nibh." page="8"/>
    <item title="Vestibulum sed libero bibendum, varius massa vitae, dictum arcu." page="19"/>
    ...
    <item title="Sed semper augue quis enim varius viverra." page="467"/>
  </item>
</outline>

Questo file contiene 70 elementi in modo che possa vedere le interruzioni di pagina.

Per costruire l'HTML e il PDF ho usato il tuo file XSL (fisso) ed eseguito pdfkit:

import io
import os

import pdfkit
from lxml import etree

HERE = os.path.dirname(__file__)


def layout(src_path, dst_path):
    # load the XSL
    xsl_path = os.path.join(HERE, "layout.xsl")
    xsl_tree = etree.parse(xsl_path)

    # load the XML source
    src_tree = etree.parse(src_path)

    # transform
    transformer = etree.XSLT(xsl_tree)
    dst_tree = transformer.apply(src_tree)

    # write the result
    with io.open(dst_path, mode="wb") as f:
        f.write(etree.tostring(dst_tree, encoding="utf-8", method="html"))


if __name__ == '__main__':
    layout(os.path.join(HERE, "outline.xml"), os.path.join(HERE, "outline.html"))
    pdfkit.from_file(os.path.join(HERE, "outline.html"),
                     os.path.join(HERE, "outline.pdf"),
                     options={'page-size': 'A1', 'orientation': 'landscape'})

nota: la tua dimensione della pagina sembra molto grande ...

Soluzione

Hai ragione, wkhtmltopdf non tiene conto del margine nel tuo CSS:

li {
  list-style: none;
  border-bottom: 1px dashed rgb(45, 117, 183);
  margin-top: 30px;  # <-- not working after page break
}

Questo è un comportamento normale, si consideri ad esempio i paragrafi di intestazione ( h1 , h2 , ecc.). Un'intestazione può avere un margine superiore per aggiungere uno spazio bianco tra un paragrafo e la seguente intestazione, ma, se l'intestazione inizia una nuova pagina, vogliamo eliminare il margine e avere l'intestazione toccando il margine superiore della pagina .

Per il tuo TOC, c'è una soluzione. È possibile utilizzare il padding (anziché il margin ):

li {
  border-bottom: 1px dashed rgb(45, 117, 183);
  list-style: none;
  padding-top: 30px;
}

In realtà, il contenuto del sommario (elemento #toc ) è fisso:

#toc {
  width: 50%;
  margin-top: 150px;
  margin-left: 300px;
}

Quindi, puoi ridurre il margin-top in base alle tue esigenze, ad esempio:

#toc {
  width: 50%;
  margin-top: 120px;
  margin-left: 300px;
}

Attualmente sto creando un PDF perfettamente funzionante. non c'è nulla di tecnicamente sbagliato in questo. Tuttavia, il sommario è brutto.

Il sommario viene generato tramite xsl che viene passato attraverso jinja2 per i dettagli semplici nella parte superiore della pagina. Ho modificato l'XSL per abbinare perfettamente il marchio e il design del cliente. Tuttavia, l'elenco continua a crescere in altezza.

Ecco il risultato corrente (mi dispiace di sfocare il testo) puoi vedere il toc che si trova nel punto giusto della nuova pagina, ma sembra che non ci sia modo di applicare un margine superiore alla nuova pagina:

Il codice: ecco la xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:outline="http://wkhtmltopdf.org/outline"
            xmlns="http://www.w3.org/1999/xhtml">
  <xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
          doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
          indent="yes" />
  <xsl:template match="outline:outline">
    <html>
      <head>
        <title>Table of Contents</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <style>

      body{
        background-color: #fff;
        margin-left: 0px;
        margin-top: 0px;
        color:#1e1e1e;
        font-family: arial, verdana,sans-serif;
        font-size: 90px;
      }
      .contentSection{
        position:relative;
        height:3200px;
        width:6100px;
      }
      .profile{
        position:absolute;
        display:inline-block;
        top:200px !important;
      }


      h1 {
        text-align: left;
        font-size: 70px;
        font-family: arial;
        color: #ef882d;
      }
      li {
        border-bottom: 1px dashed rgb(45,117,183);
      }
      span {float: right;}
      li {
        list-style: none;
        margin-top:30px;
      }
      ul {
        font-size: 70px;
        font-family: arial;
        color:#2d75b7;
      }

      ul ul {font-size: 80%; padding-top:0px;}
      ul {padding-left: 0em; padding-top:0px;}
      ul ul {padding-left: 1em; padding-top:0px;}
      a {text-decoration:none; color: color:#2d75b7;}


      #topper{
        width:100%;
        border-bottom:8px solid #ef882d;
      }
      #title{
        position:absolute;
        top:60px;
        font-size:60px;
        left:150px;
        color:#666666;
      }

      h1, h2{
        font-size:60px;
        -webkit-margin-before: 0px;
        -webkit-margin-after: 0px;
        -webkit-margin-start: 0px;
        -webkit-margin-end: 0px;
      }


      #profile{
        position:static;
        -webkit-border-top-left-radius: 40px;
        -webkit-border-bottom-left-radius: 40px;
        -moz-border-radius-topleft: 40px;
        -moz-border-radius-bottomleft: 40px;
        border-top-left-radius: 40px;
        border-bottom-left-radius: 40px;
        right:-540px;
        background-color: #2d75b7;
        padding:4px;
        padding-left:60px;
        padding-right:250px;
        color:#fff;
        display:inline-block;
        margin-top:200px;
        float:right;
      }

      #room{
        padding-top: 200px;
        padding-left: 150px;
        display:inline-block;
      }
      #section{
        padding-left: 150px;
        color: #ef882d;
        text-transform: uppercase;
        font-size:60px;
        font-weight: bold;
        display:inline-block;
        margin-top: 30px;
        margin-bottom: 5px;
      }
      #area{
        padding-left: 150px;
        font-size:60px;
        color:#2d75b7;
        margin-top: 15px;
      }
      #dims{
        padding-left: 150px;
        font-size:60px;
        color:#2d75b7;
        margin-top: 15px;
      }
      #toc{
        width:50%;
        margin-top:150px;
        margin-left:300px;
      }
    </style>
    <script>
      var value = {{profile|e}};
    </script>
  </head>
  <body>
    <div class="contentSection">
      <div id="title">A title here</div>
      <div id="topper">
        <div id="profile" class="profile">{{profile|e}}</div>
        <div id="room"> {{profile|e}} </div>
        <div id="area"> Revision Date </div>
        <div id="dims"> {{area|e}} </div>
        <div id="section">Table of Contents</div>
      </div>
      <div id="toc">
        <ul><xsl:apply-templates select="outline:item/outline:item"/></ul>
      </div>
    </div>
  </body>
</html>
 </xsl:template>
  <xsl:template match="outline:item">
    <! begin LI>
    <li>
      <xsl:if test="@title!=''">
        <div>
          <a>
            <xsl:if test="@link">
              <xsl:attribute name="href"><xsl:value-of select="@link"/> . 
 </xsl:attribute>
            </xsl:if>
            <xsl:if test="@backLink">
              <xsl:attribute name="name"><xsl:value-of select="@backLink"/> .   </xsl:attribute>
            </xsl:if>
            <xsl:value-of select="@title" />
          </a>
          <span>
            <xsl:value-of select="@page" />
          </span>
        </div>
      </xsl:if>
      <ul>
        <xsl:comment>added to prevent self-closing tags in QtXmlPatterns</xsl:comment>
        <xsl:apply-templates select="outline:item"/>
      </ul>
    </li>
  </xsl:template>
</xsl:stylesheet>

Mi sono occupato degli overflow di contenuti in altre aree del PDF utilizzando l'HTML tradizionale, JavaScript e un contrassegno pronto per il documento. Il sommario richiede tuttavia un file XSL.

Ho provato a farlo con nth-child css nth-child è ignorato.

La domanda:

* C'è un modo all'interno di wkhtmltopdf o python pdf-kit per gestire specificamente le interruzioni di pagina nel sommario e posizionare un margine migliore in cima alla nuova pagina? c'è un modo per fornire un sommario come una pagina html tradizionale in modo che io possa farlo con javaScript? *





python-pdfkit