Fullmenu null

 

25 January 2018

In this case we will do a product catalog from products of our store. It will be a Pdf with some articles and we’ll show the description, prize and a picture of the product.

We’ll use Asciidoctor. In this link you can find a basic tutorial about it (spanish) tutorial basico.
In this example we’ll use pictures from our local filesystem but also we can use links to a remote repository via http. In our case the id of every item will be the name of the picture.
Our schema will be very simple: only one table with the id, the description and the price of the article.

Considerations

Our script requires a database with the information of articles and for every one it’ll generate a page in the Pdf. We’ll use a template file common to all of them, although using a different one based on category, price, etc of each item is a trivial change.

product.tpl
.Ref: ${sku}
----
Description: ${description}

SKU ${sku}, price ${price}
----

image::${sku}.png[${description}]
catalog.tpl
= Catalog
Miguel Rueda <miguel.rueda.garcia@gmail.com>
:idprefix:
:icons: font
:imagesdir: ./images

This is our catalog of products. We hope you'll find the references you are looking for. Don't hesitate to contact
with us at 555-555-555

Environment

template=new File('./product.tpl').text
catalog= new File('./catalog.tpl').text
query='select * from products where sku < 3'

new File('.').eachFileMatch(~/.*.adoc/) { file ->
    file.delete()
}

engine = new groovy.text.SimpleTemplateEngine()

First of all we need to load the templates (product.tpl and catalog.tpl). Also we’ll need the query to read the products.

After them, the script will clean the temporary files who can be present from previous executions (files .adoc in our case)

As we want to replace the template with the values of every item we’ll use a SimpleTemplateEngine

Products

The script will iterate the select and generate one file per every item using the template product.tpl

Loading

The generateProducts() function connect with the database, execute the query (initialized at the beginning) and for every item will call createProductAdoc function:

generateProducts
void generateProducts(){
    Sql sql = Sql.newInstance( "jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
            "user",
            "password",
            "com.mysql.jdbc.Driver")
    sql.eachRow(query){item->
        createProductAdoc item
    }
}

Dump product file

Using the engine we’ll mix the values of the item with the template, generating one file per article:

createProductAdoc
def createProductAdoc(item){
    def txt = engine.createTemplate(template).make([
            'description':item.description,
            'sku':item.sku,
            'price':item.price
    ]).toString()
    new File("${item.sku}.adoc").text = txt
}

Catalog file.

To build the final catalogo.adoc file we will:

  • use the catalog.tpl template file to customize the font page and asciidoc headers

  • include previously generated files

generateCatalog
void generateCatalog() {

    def txt = engine.createTemplate(catalog).make([
            'today': new Date().format('dd/MM/yyyy HH:mm')
    ]).toString()
    new File("catalogo.adoc").text = txt

    Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
            "user",
            "password",
            "com.mysql.jdbc.Driver")
    sql.eachRow(query) { item ->
        new File("catalogo.adoc") << "include::${item.sku}.adoc[]\n"
    }
}

PDF

At the end we need to call Asciidoctor to generate the pdf using catalog.adoc :

cretatePDF
void generatePdf(){
    asciidoctor = Factory.create();
    attributes = AttributesBuilder.attributes(). // (1)
            docType('book').
            tableOfContents(true).
            sectionNumbers(true).
            sourceHighlighter("coderay").
            get()

    options = OptionsBuilder.options(). // (2)
            backend('pdf').
            attributes(attributes).
            safe(SafeMode.UNSAFE).
            get()

    asciidoctor.convertFile(new File("catalogo.adoc"), options) // (3)
}
  1. We can select different attributes as the table of content, sections, etc

  2. In this case we want a Pdf

  3. call Asciidoctor to generate the catalog.pdf

Customization

If you want you can customize the pdf with a "theme". You only need a yml file to customize the title, font, backgrounds etc. For example:

mytheme.yml
title_page: // (1)
  align: left
base:
  font_family: Times-Roman // (2)
  font_size: 12  // (3)
  1. We want the title align left

  2. We want Times-Roman as the font

  3. We can choose the size of the font

We need to indicate to Asciidoctor we want to apply this theme using the attribute pdf-style:

    asciidoctor = Factory.create();
    attributes = AttributesBuilder.attributes().attribute("pdf-style", "tema.yml").
        docType('book').
        tableOfContents(true).
        sectionNumbers(true).
        get()

Script
@Grapes([
        @Grab(group='org.asciidoctor', module='asciidoctorj', version='1.5.6'),
        @Grab(group='org.asciidoctor', module='asciidoctorj-pdf', version='1.5.0-alpha.16'),
        @Grab(group='org.jruby', module='jruby-complete', version='9.1.15.0'),
        @Grab('mysql:mysql-connector-java:5.1.6')
])
@GrabConfig(systemClassLoader=true)

import groovy.sql.Sql
import org.asciidoctor.OptionsBuilder
import org.asciidoctor.AttributesBuilder
import org.asciidoctor.SafeMode
import org.asciidoctor.Asciidoctor.Factory
//tag::prepararEntorno[]

template=new File('./product.tpl').text
catalog= new File('./catalog.tpl').text
query='select * from products where sku < 3'

new File('.').eachFileMatch(~/.*.adoc/) { file ->
    file.delete()
}

engine = new groovy.text.SimpleTemplateEngine()

//end::prepararEntorno[]

generateProducts()
generateCatalog()
generatePdf()

//tag::generateProducts[]
void generateProducts(){
    Sql sql = Sql.newInstance( "jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
            "user",
            "password",
            "com.mysql.jdbc.Driver")
    sql.eachRow(query){item->
        createProductAdoc item
    }
}
//end::generateProducts[]


//tag::create_adoc[]
def createProductAdoc(item){
    def txt = engine.createTemplate(template).make([
            'description':item.description,
            'sku':item.sku,
            'price':item.price
    ]).toString()
    new File("${item.sku}.adoc").text = txt
}
//end::create_adoc[]


//tag::create_catalog[]
void generateCatalog() {

    def txt = engine.createTemplate(catalog).make([
            'today': new Date().format('dd/MM/yyyy HH:mm')
    ]).toString()
    new File("catalogo.adoc").text = txt

    Sql sql = Sql.newInstance("jdbc:mysql://localhost:3306/origen?jdbcCompliantTruncation=false",
            "user",
            "password",
            "com.mysql.jdbc.Driver")
    sql.eachRow(query) { item ->
        new File("catalogo.adoc") << "include::${item.sku}.adoc[]\n"
    }
}
//end::create_catalog[]

//tag::create_pdf[]
void generatePdf(){
    asciidoctor = Factory.create();
    attributes = AttributesBuilder.attributes(). // (1)
            docType('book').
            tableOfContents(true).
            sectionNumbers(true).
            sourceHighlighter("coderay").
            get()

    options = OptionsBuilder.options(). // (2)
            backend('pdf').
            attributes(attributes).
            safe(SafeMode.UNSAFE).
            get()

    asciidoctor.convertFile(new File("catalogo.adoc"), options) // (3)
}
//end::create_pdf[]