Da XML a PDF
Descrivo schematicamente come produrre un documento pdf, partendo da due strutture dati XML (entrambe archiviate in una base dati MySQL) e usando la classe gratuita FPDF.
Le strutture XML
La prima struttura XML, identifica la struttura del template, e non cambia, se non cambiano chiaramente le specifiche o se si applica ad un altro formato.
E' formata da 3 elementi principali.
- Border: Per disegnare i bordi delle varie sezioni e presenta i seguenti elementi
<pos_x>9</pos_x> <pos_y>25</pos_y> <width>192</width> <height>7</height> <draw_color>0,0,0</draw_color>
- Label: Il testo che non cambiera' durante l'elaborazione.
(in futuro verra' anche questo reso parametrico, per permettere, ad esempio, le varie versioni per ogni linguaggio)
<pos_x>98</pos_x> <pos_y>26</pos_y> <font_style>Arial</font_style> <font_size>14</font_size> <font_align>L</font_align> <font_weight>B</font_weight> <font_color>0,0,0</font_color> <data>Customer ID:</data>
- Input: Il testo che potra' cambiare.
<pos_x>165</pos_x> <pos_y>53</pos_y> <width>4</width> <font_style>Arial</font_style> <font_size>8</font_size> <font_align>L</font_align> <font_weight></font_weight> <font_color>0,0,0</font_color> <font_space>0</font_space> <background_color>255,255,255</background_color> <border_input>1</border_input> <data_complete></data_complete> <data_value>LAST_NAME</data_value>
"data_complete" potra' o meno contenere un testo. Se cosi' fosse dovra' contenere il valore presente in data_value e quindi, secondo l'esempio, una cosa del genere "asd qwerty LAST_NAME zxcv"
Il "data_value" fara' riferimento alla seconda struttura XML, creata di volta in volta per ogni utente per il quale generiamo il documento.
La struttura e' semplice e si presenta cosi'
<LAST_NAME>test_contract_28</LAST_NAME>
Il codice php
Tralascio la spiegazione di come e' strutturata la classe di generazione del pdf, e mi soffermo solo su come gestisco la scrittura sul pdf dei campi variabili (Il disegno dei bordi e le label sono di una semplicita' disarmante.)
Innanzitutto leggo le due strutture con la SimpleXMLElement($xmlStr) e faccio un semplice ciclo di questo tipo.
$xmlStr = new SimpleXMLElement($xmlStr);
$xmlData = new SimpleXMLElement($xmlData);
foreach ($xmlStr->pages->page as $page) {
for($iOccurrence=1; $iOccurrence <= $page->occurrence; $iOccurrence+=1){
$pdf->AddPage();
$pdf->Image(_PATH_MAIN.'common/languages/056/en/images/logo_cw2.jpg',9,10);
$code = new pdfbarcode128($iAccountIdMain, 2 );
$code->set_pdf_document($pdf);
$code->draw_barcode(176, 12, 10, true );
... Section ...
... Label ...
// Print all the inputs
foreach ($page->inputs->input as $input) {
$this->printInput($pdf,
$input->pos_x,
$input->pos_y,
$input->width,
$input->font_style,
$input->font_size,
$input->font_align,
$input->font_weight,
$input->font_color,
$input->font_space,
$input->background_color,
$input->border_input,
$input->data_complete,
$input->data_value,
$xmlData);
}
}
}
// Output
$pdf->Output();
Nota: aggiungo anche il parametro page, che uso per sapere quante volte va generata una pagina e la generazione del barcode
Il metodo printInput(), che riceve input anche la seconda struttura XML, quella dei dati, presenta un codice di questo tipo.
private function printInput($pdf,$iPosX,$iPosY,$iWidth,$sFontStyle,$iFontSize,$sFontAlign,$sFontWeight,$sFontColor,$iFontSpace,$sBackgroundColor,$iBorderInput,$sDataComplete,$sDataValue,&$xmlData){
// iFontSpace 1: yes - 0: no
// iBorderInput 1: yes - 0: no
// sDataComplete null or string to substitute
// Insert data into a string. If it's needed.
if(!strlen($sDataComplete)){
$sStringFinal=$xmlData->{$sDataValue};
}else{
$sStringFinal=str_replace($sDataValue,$xmlData->{$sDataValue},$sDataComplete);
}
// Put the space into the character. If it's needed.
if($iFontSpace==0){
$sDataFormatFinal=$sStringFinal;
}else{
$sDataFormatFinal=preg_replace('`.(?!\z)`s','$0 ',$sStringFinal);
}
$pdf->SetFont($sFontStyle,$sFontWeight,$iFontSize);
$pdf->SetLineWidth(1/4);
$iHeight=5;
$pdf->SetDrawColor(0,0,0);
$sRGBBackgroundColor = explode(",", $sBackgroundColor);
$pdf->SetFillColor($sRGBBackgroundColor[0],$sRGBBackgroundColor[1],$sRGBBackgroundColor[2]);
$sRGBFontColor = explode(",", $sFontColor);
$pdf->SetTextColor($sRGBFontColor[0],$sRGBFontColor[1],$sRGBFontColor[2]);
$pdf->SetXY(floatval($iPosX), floatval($iPosY));
//Use iconv function because is the euro char
$pdf->MultiCell($iWidth,$iHeight,iconv("UTF-8", "CP1252",$sDataFormatFinal),$iBorderInput,1,$sFontAlign,true);
$pdf->Ln(4);
}
Notare, in particolare, come recupero il valore dalla struttura dati
$sStringFinal=$xmlData->{$sDataValue};







Linkedin
Flickr
Anobii
Youtube
Lastfm