Search code examples
grailsgroovyxhtmlhtml-to-pdf

How do I convert html to pdf with grails rendering?


I have the following template:

    <!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>template seldata</title>
    <style>
    .invoice-box {
        max-width: 800px;
        margin: auto;
        padding: 30px;
        border: 1px solid #eee;
        box-shadow: 0 0 10px rgba(0, 0, 0, .15);
        font-size: 16px;
        line-height: 24px;
        font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
        color: #555;
    }

    .invoice-box table {
        width: 100%;
        line-height: inherit;
        text-align: left;
    }

    .invoice-box table td {

        vertical-align: top;
    }


    .invoice-box table tr.top table td {
        padding-bottom: 20px;
    }

    .invoice-box table tr.top table td.title {
        font-size: 45px;
        line-height: 45px;
        color: #333;
    }

    .invoice-box table tr.information table td {
        padding-bottom: 40px;
    }

    .invoice-box table tr.heading td {
      background: #4B626D;
      border-bottom: 1px solid #ddd;

      text-align: center;
      min-width: 100px;
      color: white;
    }

    .invoice-box table tr.details td {
        padding-bottom: 20px;
    }

    .invoice-box table tr.item td{
    border-bottom: 1px solid #eee;
    text-align: center;
    }

    .invoice-box table tr.item.last td {
        border-bottom: none;
    }

    .invoice-box table tr.total td:nth-child(2) {
        border-top: 2px solid #eee;
        font-weight: bold;
    }

    @media only screen and (max-width: 600px) {
        .invoice-box table tr.top table td {
            width: 100%;
            display: block;
            text-align: center;
        }

        .invoice-box table tr.information table td {
            width: 100%;
            display: block;
            text-align: center;
        }
    }


    .rtl {
        direction: rtl;
        font-family: Tahoma, 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
    }

    .rtl table {
        text-align: right;
    }

    .rtl table tr td:nth-child(2) {
        text-align: left;
    }
    </style>
</head>

<body>
    <div class="invoice-box">
        <table>
            <tr class="top">
                <td colspan="2">
                    <table>
                        <tr>
                            <td class="title">

                            </td> 
                        </tr>
                    </table>
                </td>
            </tr>
             </table>

            <table>
            <tr class="information">
                <td colspan="2">
                    <table>
                        <tr>
                            <td>
                                <b>Data Encomenda:</b> ${poos.event_date} <br>
                                <b>Nome:</b>${poos.name}<br>
                                <b>Morada:</b> Igreja Velha - Santa Comba<br>
                                <b>Concelho:</b> Ponte de Lima<br>
                                <b>Codigo Postal:</b> 4990<br>
                                <b>Codigo da Empresa:</b> 305160<br>
                                <b>Codigo de Distribuidor:</b>00000<br>
                                Da visita ao/a V. Cunha - Ponte de Lima - JF no dia 2018-02-27 resulta o seguinte:
                            </td>


                        </tr>
                    </table>
                </td>
            </tr>
             </table>

                                <p> <b> Encomendas Grosso - Queijo e Manteiga </b> </p>

              <table>
            <tr class="heading">
                <td>
                    Marca
                </td>

                <td>
                    Produto
                </td>

                <td>
                    ID GS1
                </td>

                <td>
                    Encomenda
                </td>

                <td>
                   Data-Entrega
                </td>

                 <td>
                   Oferta
                </td>

                 <td>
                   Observações
                </td>

            </tr>

            <tr class="item">
                <td>
                    Limiano
                </td>

                <td>
                    Limiano Bola
                </td>

                 <td>
                   2902310000009
                </td>

                 <td>
                    40
                </td>

                 <td>
                    05-03-2018
                </td>

                 <td>
                    3
                </td>

                 <td>
                    1 cx em linha a parte
                </td>

            </tr>



        </table>
    </div>
</body>
</html>

I am using

ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/templates/offers", model: [poos:poos, tasks:tasks, skus:skus])

But it is throwing errors like:

org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 3; The markup in the document preceding the root element must be well-formed.

What can I do to make this work? I already made some reseach and I find this being something about XML formatting but I can't figure what is wrong. Already went to xHTML validator...

Can someone please help me to figure out how can I make this rendering work? What am I doing wrong?

(If this is exclusively to Grails Rendering, are there other html to pdf libs that I can use? )

Thanks in advance!


Solution

  • Grails Rendering Plugin - Reference Documentation

    You must declare DOCTYPE at the start of your GSP like:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    

    So your template will be _offers.gsp like follows:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
       <head>
          <meta charset="utf-8">
          <title>template seldata</title>
          <style>
             .invoice-box {
             max-width: 800px;
             margin: auto;
             padding: 30px;
             border: 1px solid #eee;
             box-shadow: 0 0 10px rgba(0, 0, 0, .15);
             font-size: 16px;
             line-height: 24px;
             font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
             color: #555;
             }
             .invoice-box table {
             width: 100%;
             line-height: inherit;
             text-align: left;
             }
             .invoice-box table td {
             vertical-align: top;
             }
             .invoice-box table tr.top table td {
             padding-bottom: 20px;
             }
             .invoice-box table tr.top table td.title {
             font-size: 45px;
             line-height: 45px;
             color: #333;
             }
             .invoice-box table tr.information table td {
             padding-bottom: 40px;
             }
             .invoice-box table tr.heading td {
             background: #4B626D;
             border-bottom: 1px solid #ddd;
             text-align: center;
             min-width: 100px;
             color: white;
             }
             .invoice-box table tr.details td {
             padding-bottom: 20px;
             }
             .invoice-box table tr.item td{
             border-bottom: 1px solid #eee;
             text-align: center;
             }
             .invoice-box table tr.item.last td {
             border-bottom: none;
             }
             .invoice-box table tr.total td:nth-child(2) {
             border-top: 2px solid #eee;
             font-weight: bold;
             }
             @media only screen and (max-width: 600px) {
             .invoice-box table tr.top table td {
             width: 100%;
             display: block;
             text-align: center;
             }
             .invoice-box table tr.information table td {
             width: 100%;
             display: block;
             text-align: center;
             }
             }
             .rtl {
             direction: rtl;
             font-family: Tahoma, 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
             }
             .rtl table {
             text-align: right;
             }
             .rtl table tr td:nth-child(2) {
             text-align: left;
             }
          </style>
       </head>
       <body>
          <div class="invoice-box">
             <table>
                <tr class="top">
                   <td colspan="2">
                      <table>
                         <tr>
                            <td class="title">
                            </td>
                         </tr>
                      </table>
                   </td>
                </tr>
             </table>
             <table>
                <tr class="information">
                   <td colspan="2">
                      <table>
                         <tr>
                            <td>
                               <b>Data Encomenda:</b> ${poos.event_date} <br>
                               <b>Nome:</b>${poos.name}<br>
                               <b>Morada:</b> Igreja Velha - Santa Comba<br>
                               <b>Concelho:</b> Ponte de Lima<br>
                               <b>Codigo Postal:</b> 4990<br>
                               <b>Codigo da Empresa:</b> 305160<br>
                               <b>Codigo de Distribuidor:</b>00000<br>
                               Da visita ao/a V. Cunha - Ponte de Lima - JF no dia 2018-02-27 resulta o seguinte:
                            </td>
                         </tr>
                      </table>
                   </td>
                </tr>
             </table>
             <p> <b> Encomendas Grosso - Queijo e Manteiga </b> </p>
             <table>
                <tr class="heading">
                   <td>
                      Marca
                   </td>
                   <td>
                      Produto
                   </td>
                   <td>
                      ID GS1
                   </td>
                   <td>
                      Encomenda
                   </td>
                   <td>
                      Data-Entrega
                   </td>
                   <td>
                      Oferta
                   </td>
                   <td>
                      Observações
                   </td>
                </tr>
                <tr class="item">
                   <td>
                      Limiano
                   </td>
                   <td>
                      Limiano Bola
                   </td>
                   <td>
                      2902310000009
                   </td>
                   <td>
                      40
                   </td>
                   <td>
                      05-03-2018
                   </td>
                   <td>
                      3
                   </td>
                   <td>
                      1 cx em linha a parte
                   </td>
                </tr>
             </table>
          </div>
       </body>
    </html>
    

    Hope this helps you