├── .gitignore
├── examples
├── pictures
│ ├── img
│ │ ├── ktip.png
│ │ ├── acroread.png
│ │ ├── kmplayer.png
│ │ ├── video-display.png
│ │ ├── view-pim-notes.png
│ │ ├── view-pim-tasks.png
│ │ ├── application-x-zerosize.png
│ │ ├── im-status-message-edit.png
│ │ ├── application-x-smb-server.png
│ │ ├── utilities-file-archiver.png
│ │ ├── application-x-smb-workgroup.png
│ │ └── preferences-desktop-cryptography.png
│ ├── pictures.ods
│ ├── pictures.pdf
│ ├── pictures-out.ods
│ ├── pictures-out.pdf
│ ├── test_pictures.php
│ ├── pictures.json
│ ├── manifest.xml
│ └── pictures-out.ods-content.xml
├── continents
│ ├── continents.ods
│ ├── continents.pdf
│ ├── continents-out.ods
│ ├── continents-out.pdf
│ ├── test_OOT.php
│ └── continents.json
├── deepdata
│ ├── deepdata-out.ods
│ ├── deepdata-out.pdf
│ ├── deepdata.json.zip
│ ├── deepdata-template.ods
│ ├── deepdata-template.pdf
│ └── deepdata.php
├── documents
│ ├── document_bill.ods
│ ├── document_bill.pdf
│ ├── img
│ │ ├── logo_empty.jpg
│ │ ├── logo_ubuntu.jpg
│ │ ├── sign_empty.jpg
│ │ ├── sign_empty.png
│ │ ├── sign_ubuntu.png
│ │ ├── stamp_empty.jpg
│ │ ├── stamp_empty.png
│ │ ├── stamp_ubuntu.png
│ │ ├── logo_libre_office.jpg
│ │ ├── logo_open_doc_template.jpg
│ │ ├── sign_libre_office_calc.png
│ │ ├── sign_open_doc_template.png
│ │ ├── stamp_libre_office_calc.png
│ │ └── stamp_open_doc_template.png
│ ├── document_bill-out.ods
│ ├── document_bill-out_sample2.pdf
│ ├── document_bill-out_ubuntu_stamp.pdf
│ ├── test_document.php
│ ├── documents.json
│ ├── README.md
│ ├── content.xml
│ └── document_bill-out.ods-content.xml
└── text_document
│ ├── text_doc-out.odt
│ ├── text_doc-template.odt
│ ├── data.php
│ └── text_doc.php
├── docs
└── img
│ ├── continents_template_out.jpg
│ ├── continents_template_src.jpg
│ ├── deepdata_template_out.jpg
│ ├── deepdata_template_src.jpg
│ ├── document_template_out.jpg
│ ├── document_template_src.jpg
│ ├── pictures_template_out.jpg
│ ├── pictures_template_src.jpg
│ ├── document_template_out_libre.png
│ ├── document_template_out_ubuntu.png
│ ├── document_template_src_named.jpg
│ ├── document_template_src_img_anchor.png
│ ├── document_template_src_properties.jpg
│ └── document_template_src_virtual_fields.png
├── composer.json
├── README.md
└── OpenDocumentTemplate.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .directory
2 | .~*
3 | .swp
4 |
--------------------------------------------------------------------------------
/examples/pictures/img/ktip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/ktip.png
--------------------------------------------------------------------------------
/examples/pictures/pictures.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/pictures.ods
--------------------------------------------------------------------------------
/examples/pictures/pictures.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/pictures.pdf
--------------------------------------------------------------------------------
/docs/img/continents_template_out.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/continents_template_out.jpg
--------------------------------------------------------------------------------
/docs/img/continents_template_src.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/continents_template_src.jpg
--------------------------------------------------------------------------------
/docs/img/deepdata_template_out.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/deepdata_template_out.jpg
--------------------------------------------------------------------------------
/docs/img/deepdata_template_src.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/deepdata_template_src.jpg
--------------------------------------------------------------------------------
/docs/img/document_template_out.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_out.jpg
--------------------------------------------------------------------------------
/docs/img/document_template_src.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_src.jpg
--------------------------------------------------------------------------------
/docs/img/pictures_template_out.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/pictures_template_out.jpg
--------------------------------------------------------------------------------
/docs/img/pictures_template_src.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/pictures_template_src.jpg
--------------------------------------------------------------------------------
/examples/continents/continents.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/continents/continents.ods
--------------------------------------------------------------------------------
/examples/continents/continents.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/continents/continents.pdf
--------------------------------------------------------------------------------
/examples/deepdata/deepdata-out.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/deepdata/deepdata-out.ods
--------------------------------------------------------------------------------
/examples/deepdata/deepdata-out.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/deepdata/deepdata-out.pdf
--------------------------------------------------------------------------------
/examples/deepdata/deepdata.json.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/deepdata/deepdata.json.zip
--------------------------------------------------------------------------------
/examples/documents/document_bill.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/document_bill.ods
--------------------------------------------------------------------------------
/examples/documents/document_bill.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/document_bill.pdf
--------------------------------------------------------------------------------
/examples/pictures/img/acroread.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/acroread.png
--------------------------------------------------------------------------------
/examples/pictures/img/kmplayer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/kmplayer.png
--------------------------------------------------------------------------------
/examples/pictures/pictures-out.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/pictures-out.ods
--------------------------------------------------------------------------------
/examples/pictures/pictures-out.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/pictures-out.pdf
--------------------------------------------------------------------------------
/examples/continents/continents-out.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/continents/continents-out.ods
--------------------------------------------------------------------------------
/examples/continents/continents-out.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/continents/continents-out.pdf
--------------------------------------------------------------------------------
/examples/documents/img/logo_empty.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/logo_empty.jpg
--------------------------------------------------------------------------------
/examples/documents/img/logo_ubuntu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/logo_ubuntu.jpg
--------------------------------------------------------------------------------
/examples/documents/img/sign_empty.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/sign_empty.jpg
--------------------------------------------------------------------------------
/examples/documents/img/sign_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/sign_empty.png
--------------------------------------------------------------------------------
/examples/documents/img/sign_ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/sign_ubuntu.png
--------------------------------------------------------------------------------
/examples/documents/img/stamp_empty.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/stamp_empty.jpg
--------------------------------------------------------------------------------
/examples/documents/img/stamp_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/stamp_empty.png
--------------------------------------------------------------------------------
/docs/img/document_template_out_libre.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_out_libre.png
--------------------------------------------------------------------------------
/docs/img/document_template_out_ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_out_ubuntu.png
--------------------------------------------------------------------------------
/docs/img/document_template_src_named.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_src_named.jpg
--------------------------------------------------------------------------------
/examples/deepdata/deepdata-template.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/deepdata/deepdata-template.ods
--------------------------------------------------------------------------------
/examples/deepdata/deepdata-template.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/deepdata/deepdata-template.pdf
--------------------------------------------------------------------------------
/examples/documents/document_bill-out.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/document_bill-out.ods
--------------------------------------------------------------------------------
/examples/documents/img/stamp_ubuntu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/stamp_ubuntu.png
--------------------------------------------------------------------------------
/examples/pictures/img/video-display.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/video-display.png
--------------------------------------------------------------------------------
/examples/pictures/img/view-pim-notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/view-pim-notes.png
--------------------------------------------------------------------------------
/examples/pictures/img/view-pim-tasks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/view-pim-tasks.png
--------------------------------------------------------------------------------
/examples/text_document/text_doc-out.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/text_document/text_doc-out.odt
--------------------------------------------------------------------------------
/docs/img/document_template_src_img_anchor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_src_img_anchor.png
--------------------------------------------------------------------------------
/docs/img/document_template_src_properties.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_src_properties.jpg
--------------------------------------------------------------------------------
/examples/documents/img/logo_libre_office.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/logo_libre_office.jpg
--------------------------------------------------------------------------------
/examples/text_document/text_doc-template.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/text_document/text_doc-template.odt
--------------------------------------------------------------------------------
/examples/documents/document_bill-out_sample2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/document_bill-out_sample2.pdf
--------------------------------------------------------------------------------
/examples/pictures/img/application-x-zerosize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/application-x-zerosize.png
--------------------------------------------------------------------------------
/examples/pictures/img/im-status-message-edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/im-status-message-edit.png
--------------------------------------------------------------------------------
/docs/img/document_template_src_virtual_fields.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/docs/img/document_template_src_virtual_fields.png
--------------------------------------------------------------------------------
/examples/documents/img/logo_open_doc_template.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/logo_open_doc_template.jpg
--------------------------------------------------------------------------------
/examples/documents/img/sign_libre_office_calc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/sign_libre_office_calc.png
--------------------------------------------------------------------------------
/examples/documents/img/sign_open_doc_template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/sign_open_doc_template.png
--------------------------------------------------------------------------------
/examples/documents/img/stamp_libre_office_calc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/stamp_libre_office_calc.png
--------------------------------------------------------------------------------
/examples/documents/img/stamp_open_doc_template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/img/stamp_open_doc_template.png
--------------------------------------------------------------------------------
/examples/pictures/img/application-x-smb-server.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/application-x-smb-server.png
--------------------------------------------------------------------------------
/examples/pictures/img/utilities-file-archiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/utilities-file-archiver.png
--------------------------------------------------------------------------------
/examples/documents/document_bill-out_ubuntu_stamp.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/documents/document_bill-out_ubuntu_stamp.pdf
--------------------------------------------------------------------------------
/examples/pictures/img/application-x-smb-workgroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/application-x-smb-workgroup.png
--------------------------------------------------------------------------------
/examples/pictures/img/preferences-desktop-cryptography.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xv1t/OpenDocumentTemplate/HEAD/examples/pictures/img/preferences-desktop-cryptography.png
--------------------------------------------------------------------------------
/examples/continents/test_OOT.php:
--------------------------------------------------------------------------------
1 | open('continents.ods', 'continents-out.ods', 'continents.json', array(
8 | 'hide_draws' => array(
9 | 'ImageNULL'
10 | )
11 | ));
12 |
--------------------------------------------------------------------------------
/examples/pictures/test_pictures.php:
--------------------------------------------------------------------------------
1 | open('pictures.ods', 'pictures-out.ods', 'pictures.json', array(
8 | 'with_image_dir' => 'img',
9 | 'extract_content' => true
10 | ));
11 |
12 | //print_r($od->meta);
13 | //print_r($od->schema);
14 |
15 | print_r($od->used_images);
16 |
--------------------------------------------------------------------------------
/examples/text_document/data.php:
--------------------------------------------------------------------------------
1 | array(
5 | 'name' => 'The report main name!',
6 | 'date' => date('c'),
7 | 'title' => 'Contract 34',
8 | 'author' => 'user@localhost',
9 | 'picture' => 'acroread.png'
10 | ),
11 | 'Document' => array(
12 | 'address' => 'Mella st. 123-2 JK fede'
13 | ),
14 | 'Author' => array(
15 | 'name' => 'R. Sabbatinique'
16 | )
17 | );
18 |
--------------------------------------------------------------------------------
/examples/deepdata/deepdata.php:
--------------------------------------------------------------------------------
1 | open('deepdata.json.zip');
9 | echo "unzip deepdata.json\n";
10 | $data = json_decode( $zip->getFromName('deepdata.json'), true );
11 |
12 | $zip->close();
13 |
14 | echo "Build report...\n";
15 | $od->open('deepdata-template.ods', 'deepdata-out.ods', $data, array(
16 | // 'with_image_dir' => 'img',
17 | // 'extract_content' => true,
18 | // 'dom_stay' => true
19 | ));
20 |
21 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xv1t/opendocument-template",
3 | "description": "Rendering templates with multidimensional data into a reports",
4 | "keywords": ["template", "render", "ods", "libreoffice", "report"],
5 | "license": "MIT",
6 | "homepage": "https://github.com/xv1t/OpenDocumentTemplate",
7 | "authors": [
8 | {
9 | "name": "Victor Fedotov",
10 | "email": "xv1t@yandex.ru"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=5.3.0",
15 | "ext-zip": "*",
16 | "ext-xml": "*"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/documents/test_document.php:
--------------------------------------------------------------------------------
1 | open('document_bill.ods', 'document_bill-out.ods', 'documents.json', array(
8 | 'with_image_dir' => 'img',
9 | 'extract_content' => true,
10 | 'dom_stay' => true
11 | ));
12 |
13 | //print_r($od->meta);
14 | $sheet = $od->dom->getElementsByTagName('table')->item(0);
15 | $xpath = new DOMXPath($od->dom);
16 |
17 | $items = $xpath->query("table:table-row/table:table-cell[@table:number-rows-spanned]", $sheet);
18 |
19 | //print_r($items[0]);
20 | //print_r($od->data);
21 | //print_r($od->schema['named-range']);
22 |
23 | print_r($od->used_images);
24 | echo(1234);
25 | $data = json_decode( file_get_contents( 'documents.json' ), true);
26 | var_dump($data);
27 | print_r( $data );
28 |
--------------------------------------------------------------------------------
/examples/text_document/text_doc.php:
--------------------------------------------------------------------------------
1 | open('text_doc-template.odt', 'text_doc-out.odt', $data, array(
10 | // 'with_image_dir' => 'img',
11 | // 'extract_content' => true,
12 | 'with_image_dir' => '../pictures/img',
13 | 'dom_stay' => true
14 | ));
15 |
16 | $text = $od->dom->getElementsByTagName('text')->item(0);
17 |
18 | $para = $text->getElementsByTagName('p');
19 | print_r($para);
20 |
21 | foreach ($para as $p){
22 | $textContent = $p->textContent;
23 | $childNodes = $p->childNodes->length;
24 | $firstChildTextContent = null;
25 |
26 | $childnodes = array();
27 |
28 | if (!empty($p->childNodes)){
29 | foreach ($p->childNodes as $childNode){
30 | $childnodes[] = $childNode->textContent;
31 | }
32 | }
33 |
34 | //print_r(compact('textContent', 'childNodes', 'childnodes', 'p'));
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/examples/pictures/pictures.json:
--------------------------------------------------------------------------------
1 | {
2 | "Report": {
3 | "title": "Data with pictures example"
4 |
5 | },
6 | "People": [
7 | {
8 | "Person": {
9 | "name": "Took Adalva",
10 | "title": "Izvr Magistr",
11 | "image": "acroread.png",
12 | "money": 12.34
13 | }
14 | },
15 | {
16 | "Person": {
17 | "name": "Googve",
18 | "title": "Devon Otver",
19 | "image": "im-status-message-edit.png",
20 | "money": 6.7
21 | }
22 | },
23 | {
24 | "Person": {
25 | "name": "Boorva",
26 | "title": "Grevuan Octanr",
27 | "image": "kmplayer.png" ,
28 | "money": 0
29 | }
30 | },
31 | {
32 | "Person": {
33 | "name": "Grigge",
34 | "title": "Fuurm Horsd",
35 | "image": false,
36 | "money": 15.76
37 | }
38 | },
39 | {
40 | "Person": {
41 | "name": "muarge",
42 | "title": "Thimd",
43 | "image": "ktip.png",
44 | "money": 15.76
45 | }
46 | },
47 | {
48 | "Person": {
49 | "name": "Jant",
50 | "title": "Qwerbg",
51 | "image": "utilities-file-archiver.png",
52 | "money": 10.54
53 | }
54 | },
55 | {
56 | "Person": {
57 | "name": "Tika",
58 | "title": "Qwerbg",
59 | "image": "acroread.png",
60 | "money": 3.45
61 | }
62 | },
63 | {
64 | "Person": {
65 | "name": "Atlam",
66 | "title": "--",
67 | "image": "video-display.png",
68 | "money": 0.6
69 | }
70 | }
71 | ]
72 | }
--------------------------------------------------------------------------------
/examples/documents/documents.json:
--------------------------------------------------------------------------------
1 | {
2 | "Document": {
3 | "name": "Bill",
4 | "number": "123/A9",
5 | "date": "2016-09-23",
6 | "manager": "Gretto Uzz",
7 | "stamp": "stamp_libre_office_calc.png",
8 | "sign": "sign_open_doc_template.png"
9 | },
10 | "Supplier": {
11 | "logo" : "logo_open_doc_template.jpg",
12 | "name": "Open source shot test",
13 | "address": "The city of the country, 123-23FZ",
14 | "email": "mail@example.free"
15 | },
16 | "Buyer": {
17 | "name": "Typical customer",
18 | "address": "My country",
19 | "email": "mail@sample.com"
20 | },
21 | "Goods": [
22 | {
23 | "Good": {
24 | "name": "Cofee",
25 | "cost": 6.45,
26 | "count": 4
27 | }
28 | },
29 | {
30 | "Good": {
31 | "name": "Disk",
32 | "cost": 0.17,
33 | "count": 3
34 | }
35 | },
36 | {
37 | "Good": {
38 | "name": "Book",
39 | "cost": 2.30,
40 | "count": 3
41 | }
42 | },
43 | {
44 | "Good": {
45 | "name": "USB Flash",
46 | "cost": 19,
47 | "count": 2
48 | }
49 | },
50 | {
51 | "Good": {
52 | "name": "Floppy disk",
53 | "cost": 1.01,
54 | "count": 10
55 | }
56 | },
57 | {
58 | "Good": {
59 | "name": "Manual PDF",
60 | "cost": 0.0,
61 | "count": 1
62 | }
63 | },
64 | {
65 | "Good": {
66 | "name": "Hat",
67 | "cost": 17.34,
68 | "count": 7
69 | }
70 | },
71 | {
72 | "Good": {
73 | "name": "Pen",
74 | "cost": 0.87,
75 | "count": 26
76 | }
77 | },
78 | {
79 | "Good": {
80 | "name": "Keyboard AB",
81 | "cost": 16.04,
82 | "count": 8
83 | }
84 | }
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/examples/pictures/manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
| [Supplier.logo]
9 | Stamp | 400×400 |
| [Document.stamp]
10 | Sign | 685×350 |
| [Document.sign]
11 |
12 | If you planing use different images, firstly you make a dummy version of images, and working
13 | image sizes must be identically!
14 |
15 | ## Stamps
16 | stamp_libre_office_calc.png|stamp_open_doc_template.png|stamp_ubuntu.png
17 | :------:|:-----:|:-----:
18 |
|
|
19 |
20 | ## Logos
21 | Picture | File
22 | ------|-----
23 |  |logo_libre_office.jpg
24 |  |logo_open_doc_template.jpg
25 |  | logo_ubuntu.jpg
26 |
27 | ## Signs
28 | sign_libre_office_calc.png | sign_open_doc_template.png | sign_ubuntu.png
29 | --------|------|-----|
30 |  | |
31 |
32 | ## Image folder
33 | All image put in the once folder `img`
34 |
35 | # 2. Prepare data array
36 | Our `$data` in this example is a array and it have following keys:
37 | ```php
38 | $data = array(
39 | 'Document' => /*...*/,
40 | 'Supplier' => /*...*/,
41 | 'Buyer' => /*...*/
42 | );
43 | ```
44 | ## Linear object notation.
45 | Keys `Document`, `Supplier`, `Buyer` - is a linear object keys
46 | ```php
47 | $data = array(
48 | 'Document' => array(
49 | 'name' => 'Bill',
50 | 'number' => '123/A9',
51 | 'date' => '2016-09-23',
52 | 'manager' => '',
53 | 'stamp' => 'stamp_open_doc_template.png',
54 | 'sign' => 'sign_open_doc_template.png'
55 | ),
56 | 'Supplier' => array(
57 | 'logo' => 'logo_libre_office.jpg',
58 | 'name' => "Open source shot test",
59 | 'address' => "The city of the country, 123-23FZ",
60 | 'email' => 'mail@example.free'
61 | ),
62 | 'Buyer' => array(
63 | 'name' => 'Typical customer',
64 | 'address' => 'My country',
65 | 'email' => 'mail@sample.com'
66 | ),
67 | );
68 | ```
69 |
70 | ## Next deep level data
71 | Add a key `Goods` is contain a list of objects.
72 | ```php
73 | $data = array(
74 | 'Document' => /*...*/,
75 | 'Supplier' => /*...*/,
76 | 'Buyer' => /*...*/
77 | 'Goods' => array( //key for list of goods objects
78 | array(/*...*/),
79 | array(/*...*/),
80 | array(/*...*/),
81 | array(/*...*/),
82 | array(/*...*/),
83 | array(/*...*/),
84 | array(/*...*/),
85 | )
86 | );
87 | ```
88 | And each `Good` object fill as
89 | ```php
90 | array(
91 | 'Goods' => array(
92 | array('Good' => array(/*...*/)),
93 | array('Good' => array(/*...*/)),
94 | array('Good' => array(/*...*/)),
95 | array('Good' => array(/*...*/)),
96 | array('Good' => array(/*...*/)),
97 | array('Good' => array(/*...*/)),
98 | array('Good' => array(/*...*/)),
99 | )
100 | )
101 | ```
102 | Add all field for each `Good` contain a kes: `name`, `cost`, `count`
103 | ```php
104 | $data = array(
105 | 'Document' => array(
106 | 'name' => 'Bill',
107 | 'number' => '123/A9',
108 | 'date' => '2016-09-23',
109 | 'manager' => '',
110 | 'stamp' => 'stamp_open_doc_template.png',
111 | 'sign' => 'sign_open_doc_template.png'
112 | ),
113 | 'Supplier' => array(
114 | 'logo' => 'logo_libre_office.jpg',
115 | 'name' => "Open source shot test",
116 | 'address' => "The city of the country, 123-23FZ",
117 | 'email' => 'mail@example.free'
118 | ),
119 | 'Buyer' => array(
120 | 'name' => 'Typical customer',
121 | 'address' => 'My country',
122 | 'email' => 'mail@sample.com'
123 | ),
124 | 'Goods' => array( //This list of data next dimension
125 | array(
126 | 'Good' => array(
127 | 'name' => 'Cofee',
128 | 'cost' => 6.45,
129 | 'count' => 4,
130 | )
131 | ),
132 | array(
133 | 'Good' => array(
134 | 'name' => 'Disk',
135 | 'cost' => 0.17,
136 | 'count' => 3,
137 | )
138 | ),
139 | array(
140 | 'Good' => array(
141 | 'name' => 'Book',
142 | 'cost' => 2.30,
143 | 'count' => 3,
144 | )
145 | ),
146 | array(
147 | 'Good' => array(
148 | 'name' => 'USB Flash',
149 | 'cost' => 19,
150 | 'count' => 2,
151 | )
152 | ),
153 | array(
154 | 'Good' => array(
155 | 'name' => 'Floppy disk',
156 | 'cost' => 1.01,
157 | 'count' => 10,
158 | )
159 | ),
160 | array(
161 | 'Good' => array(
162 | 'name' => 'Manual PDF',
163 | 'cost' => 9,
164 | 'count' => 1,
165 | )
166 | ),
167 | array(
168 | 'Good' => array(
169 | 'name' => 'Hat',
170 | 'cost' => 17.34,
171 | 'count' => 7
172 | )
173 | ),
174 | array(
175 | 'Good' => array(
176 | 'name' => 'Pen',
177 | 'cost' => 0.87,
178 | 'count' => 26
179 | )
180 | ),
181 | array(
182 | 'Good' => array(
183 | 'name' => 'Keyboard AB',
184 | 'cost' => 16.04,
185 | 'count' => 8
186 | )
187 | ),
188 | )
189 | );
190 | ```
191 |
192 | # 3. Design template
193 | Design template file `document_bill.ods`
194 | 
195 |
196 | ## Data field notation
197 | All data fields writes on cells:
198 |
199 | Example | Value in the report |
200 | --------|------------
201 | [Good.name] | Book
202 | [Document.name] [Document.number] as [Document.date] | Bill 123/A9 at 2016-09-23
203 |
204 | ## Named range of items
205 | Row `10` is a named range by name `Goods`.
206 |
207 | Range option
208 |
209 | - [x] Repeat row
210 | 
211 |
212 |
213 | ## Images
214 | All images need `Anchor` to `cell`. If select image, then be visible a anchor icon on the cell
215 |
216 |
217 |
218 | ## Image names
219 | If you want dinamic change image source, then set name to field name of current object,
220 |
221 | Logo | Stamp | Sign
222 | -----------------|--------|---------
223 | [Supplier.logo] | [Document.stamp] | [Document.sign]
224 |
225 | ```php
226 | $data = array(
227 | 'Document' => array(
228 | /*...*/
229 | 'stamp' => 'stamp_open_doc_template.png', //stamp image, image name: [Document.stamp]
230 | 'sign' => 'sign_open_doc_template.png' //sign image, image name : [Document.sign]
231 | ),
232 | 'Supplier' => array(
233 | 'logo' => 'logo_libre_office.jpg', //logo image name, image name: [Supplier.logo]
234 | /*...*/
235 | ),
236 | 'Buyer' => array(/*..*/),
237 | 'Goods' => array(/*..*/),
238 | ```
239 | );
240 |
241 | ## Virtual fields
242 | In the good we have a two numeric fields: `cost`, `count`.
243 | But what about a value of `cost * count`?
244 |
245 | Virtual field | Formula
246 | --------------|-----------
247 | [Good.total] | [Good.cost]*[Good.count]
248 | [Good.tax] | [Good.total] * 0.18
249 | [Good.with_tax] | [Good.with_tax]
250 |
251 | On the spreedsheet in the cell with virtual field add a `Comment` and write formula, such as
252 | 
253 |
254 | ## Aggregate function `COUNT()`
255 | All values `COUNT()` for defined named ranges automaticaly calculated
256 | Examples
257 |
258 | Named range | cell template value | Report value
259 | ------------|-----------------------|----------
260 | Goods | [COUNT(Goods)] | 8
261 | Countries | [COUNT(Countries)] | 3
262 |
263 | ## SUM()
264 |
265 | Set properties for define aggregate `SUM()` functions:
266 |
267 | 
268 |
269 | In the `LibreOffice Calc` click `File`/`Properties` - tab `Custom properties`
270 | And cells with values: `[SUM(Good.tax)]`, `[SUM(Good.total)]` and other are correctly to sum
271 |
272 | # And render our template
273 | ```php
274 | open('document_bill.ods', 'document_bill-out.ods', $data, array(
281 | 'with_image_dir' => 'img/', //this path of your images folder
282 | ));
283 | ```
284 |
285 | And open new file `document_bill-out.ods` in the libre office and show print preview
286 |
287 | 
288 |
289 | Change the image names and your reports be a differents!
290 |
291 | 
292 |
293 | 
294 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Project name | OpenDocumentTemplate
2 | -------------|---------------------
3 | Language | PHP
4 | Source files | ODS, ODT
5 |
6 |
7 | #Fast generation OpenDocument reports
8 | Support files: `ODS`, `ODT`
9 |
10 | Template | Report
11 | ----------|-------
12 | [  ](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/documents) Bill document template (ODS) | [  ](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/documents) See the great manual [/examples/documents](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/documents)
13 |  Simple cards with data (ODS) |  [/examples/continents](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/continents)
14 |  Dynamic pictures (ODS) |  [/examples/pictures](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/pictures)
15 |  15 level deep dimensions (ODS) |  [/examples/deepdata](https://github.com/xv1t/OpenDocumentTemplate/tree/master/examples/deepdata)
16 |
17 | Recommended software for create template
18 | * LibreOffice
19 | * OpenOffice
20 |
21 | Your done report files was correct opened in
22 | * LibreOffice
23 | * OpenOffice
24 | * MS Office >=2010
25 |
26 | ## Fast manual (ods)
27 | 1. Create template ods file
28 | 2. Put elements
29 | 3. Mark ranges
30 | 4. Load data from database
31 | 5. Render data through template file info your new ods file
32 | 6. Open in the LibreOffice Calc or other and enjoy
33 |
34 |
35 | ## Requirements
36 | Php extensions
37 | * zip
38 | * xml
39 |
40 | Php version >=5.3
41 |
42 | Recommended sowfware for templating: LibreOffice 5
43 |
44 | ## Install
45 | Put file `OpenDocumentTemplate.php` into your project, and use it
46 | ```php
47 | array(
66 | 'name' => 'Test Report',
67 | 'date' => '2016-09-25',
68 | 'author' => 'Me'
69 | )
70 | );
71 | ```
72 | All fields grouping in the `Report` parent array.
73 | This method of naming provides a powerful technique for multidimensional data.
74 |
75 | ## Design template file
76 | Open the LibreOffice Calc. Create new spreedsheet;
77 |
78 | add a 3 cells for next contents:
79 |
80 | [] |A | B | C |
81 | ---|----|---|------|
82 | 1 | [Report.name] | [Report.date] | [Report.author]
83 | 2 | | |
84 | 3 | | |
85 |
86 | Save it with name `sample_report.ods`.
87 |
88 | ## Render template with data
89 | ```php
90 | open('sample_report.ods', 'sample_report-out.ods', $data)
92 | ```
93 | And open new file `sample_report-out.ods` and you see in sheet:
94 |
95 | [] |A | B | C
96 | ---|---|---|----
97 | 1 |Test Report | 2016-09-25 | Me
98 | 2 | | |
99 | 3 | | |
100 |
101 | ## Add second dimension
102 | Add a key `Cities` for the list of objects
103 | ```php
104 | array(/* main Report data */),
107 | 'Cities' => array(
108 | array(/* city data */),
109 | array(/* city data */),
110 | array(/* city data */),
111 | array(/* city data */),
112 | )
113 | );
114 | ```
115 |
116 | All `Cities` object must be have an identical list of the fields. In our example: `name`, `streets`, `population`
117 | ```php
118 | array(
123 | 'name' => 'Albatros',
124 | 'streets' => 165,
125 | 'population' => 1300000
126 | )
127 | );
128 | ```
129 |
130 | And all data
131 | ```php
132 | $data = array(
133 | 'Report' => array(
134 | 'name' => 'Test Report',
135 | 'date' => '2016-09-25',
136 | 'author' => 'Me'
137 | ),
138 | 'Cities' => array(
139 | array( //first object
140 | 'City' => array(
141 | 'name' => 'Albatros',
142 | 'streets' => 165,
143 | 'population' => 1300000
144 | )
145 | ),
146 | array( //next object
147 | 'City' => array(
148 | 'name' => 'Turtuga',
149 | 'streets' => 132,
150 | 'population' => 750000
151 | )
152 | ),
153 | array( //next object
154 | 'City' => array(
155 | 'name' => 'Palmtown',
156 | 'streets' => 18,
157 | 'population' => 10000
158 | )
159 | ),
160 | )
161 | );
162 | ```
163 | ## Add a other object as linear dimesion
164 | Add inforamation about the mayor of the each city, in the sibling key `Mayor`
165 | ```php
166 | array(/*...*/),
170 | 'Cities' => array(
171 | array(
172 | 'City' => array(/*...*/),
173 | 'Mayor' => array(
174 | 'name' => 'John Do',
175 | 'old' => 47
176 | ),
177 | ),
178 | array(
179 | 'City' => array(/*...*/),
180 | 'Mayor' => array(
181 | 'name' => 'Mary Ann',
182 | 'old' => 32
183 | ),
184 | ),
185 | array(
186 | 'City' => array(/*...*/),
187 | 'Mayor' => array(
188 | 'name' => 'Mike Tee',
189 | 'old' => 29
190 | ),
191 | ),
192 | )
193 | );
194 | ```
195 |
196 | ## Add third dimesions
197 | Add a key `Squares` for the list of the squares in the each city
198 |
199 | ```php
200 | array(/*...*/),
203 | 'Cities' => array(
204 | array(
205 | 'City' => array(/*...*/),
206 | 'Mayor' => array(/*...*/),
207 | 'Squares' => array(
208 | array(/*...*/),
209 | array(/*...*/),
210 | array(/*...*/),
211 | )
212 | ),
213 | array(
214 | 'City' => array(/*...*/),
215 | 'Mayor' => array(/*...*/),
216 | 'Squares' => array(
217 | array(/*...*/),
218 | array(/*...*/),
219 | array(/*...*/),
220 | array(/*...*/),
221 | array(/*...*/),
222 | )
223 | ),
224 | array(
225 | 'City' => array(/*...*/),
226 | 'Mayor' => array(/*...*/),
227 | 'Squares' => array(
228 | array(/*...*/),
229 | array(/*...*/),
230 | )
231 | ),
232 |
233 | )
234 | );
235 | ```
236 | Example Square object:
237 | ```php
238 | array(
241 | 'name' => 'Trafalgaar',
242 | 'length' => 23,
243 | 'width' => 45
244 | )
245 | )
246 | ```
247 |
248 | And out `$data` finish version:
249 | ```php
250 | array(
255 | 'name' => 'Test Report',
256 | 'date' => '2016-09-25',
257 | 'author' => 'Me'
258 | ),
259 | 'Cities' => array(
260 | array(
261 | //level 2
262 | 'City' => array(
263 | 'name' => 'Albatros',
264 | 'streets' => 165,
265 | 'population' => 1300000
266 | )
267 | 'Mayor' => array(
268 | 'name' => 'John Do',
269 | 'old' => 47
270 | ),
271 | 'Squares' => array(
272 | array(
273 | //level 3
274 | 'Sqaure' => array(
275 | 'name' => 'Trafalgaar',
276 | 'length' => 23,
277 | 'width' => 45
278 | )
279 | ),
280 | array(
281 | 'Sqaure' => array(
282 | 'name' => 'Square #2',
283 | 'length' => 23,
284 | 'width' => 45
285 | )
286 | ),
287 | array(
288 | 'Sqaure' => array(
289 | 'name' => 'Square #3',
290 | 'length' => 23,
291 | 'width' => 45
292 | )
293 | ),
294 | )
295 | ),
296 | array(
297 | 'City' => array(
298 | 'name' => 'Turtuga',
299 | 'streets' => 132,
300 | 'population' => 750000
301 | )
302 | 'Mayor' => array(
303 | 'name' => 'Mary Ann',
304 | 'old' => 32
305 | ),
306 | 'Squares' => array(
307 | array(
308 | 'Sqaure' => array(
309 | 'name' => 'Square #4',
310 | 'length' => 23,
311 | 'width' => 45
312 | )
313 | ),
314 | array(
315 | 'Sqaure' => array(
316 | 'name' => 'Square #5',
317 | 'length' => 23,
318 | 'width' => 45
319 | )
320 | ),
321 | )
322 | ),
323 | array(
324 | 'City' => array(
325 | 'name' => 'Palmtown',
326 | 'streets' => 18,
327 | 'population' => 10000
328 | ),
329 | 'Mayor' => array(
330 | 'name' => 'Mike Tee',
331 | 'old' => 29
332 | ),
333 | 'Squares' => array(
334 | array(
335 | 'Sqaure' => array(
336 | 'name' => 'Square #6',
337 | 'length' => 23,
338 | 'width' => 45
339 | )
340 | ),
341 | array(
342 | 'Sqaure' => array(
343 | 'name' => 'Square #7',
344 | 'length' => 23,
345 | 'width' => 45
346 | )
347 | ),
348 | array(
349 | 'Sqaure' => array(
350 | 'name' => 'Square #8',
351 | 'length' => 23,
352 | 'width' => 45
353 | )
354 | ),
355 | )
356 | ),
357 | )
358 | );
359 | ```
360 | ## Design a spreedsheet
361 |
362 | [] | A | B | C | D | E
363 | ---|---|---|---|---|----
364 | 1 | [Report.name] | | Author | [Report.author]
365 | 2 | **Cities**
366 | 3 | | City | [City.name]
367 | 4 | | Streets | [City.streets]
368 | 5 | | Population | [City.population]
369 | 6 | | Mayor | [Mayor.name]
370 | 7 | | **Squares**
371 | 8 | | | name | length | width
372 | 9 | | | [Square.name] | [Square.length] | [Square.width]
373 | 11 | | Squares count | [COUNT(Squares)]
374 | 12 | Cities count | [COUNT(Cities)]
375 | 13 | Report date | [Report.date]
376 |
377 |
378 |
379 | Well, we have a 3 level dimension array of objects:
380 |
381 | In LibreOffice Calc they are called `Range names`.
382 |
383 | `Insert` -> `Names` => `Manage`
384 |
385 |
386 | # Examples
387 |
388 |
389 |
--------------------------------------------------------------------------------
/examples/documents/content.xml:
--------------------------------------------------------------------------------
1 |
2 |
30 | * Path to source ods or odt file 31 | *
32 | * @param string $out_file33 | * Path to result file 34 | *
35 | * @param mixed $data36 | * Structured array, or path to json file with data 37 | *
38 | * @param array $options39 | * Options 40 | *
41 | */ 42 | public function open($template_file, $out_file, $data, $options = array()) { 43 | if (empty($this->dom)) { 44 | $this->dom = new DOMDocument; 45 | } 46 | $zip = new ZipArchive; 47 | $zip->open($template_file); 48 | $this->mimetype = $zip->getFromName('mimetype'); 49 | 50 | $this->dom->loadXML($zip->getFromName('meta.xml')); 51 | $this->read_meta(); 52 | 53 | $this->dom->loadXML($zip->getFromName('content.xml')); 54 | $zip->close(); 55 | 56 | if (is_string($data) && file_exists($data)){ 57 | $data = json_decode(file_get_contents($data), true ); 58 | } 59 | 60 | if (empty($data)){ 61 | $data = array(); 62 | } 63 | 64 | //prepare data 65 | $data += array( 66 | 'now' => date('Y-m-d'), 67 | 'now_datetime' => date('Y-m-d H:i:i'), 68 | 'datetime' => date('Y-m-d H:i:i'), 69 | 'now_time' => date('H:i:s'), 70 | 'time' => date('H:i:s'), 71 | 'template_file' => $template_file, 72 | 'out_file' => $out_file 73 | ); 74 | 75 | //populate data to object property 76 | $this->data = $data; 77 | switch ($this->mimetype) { 78 | case 'application/vnd.oasis.opendocument.spreadsheet': 79 | $this->ods_analyze(); 80 | $this->ods_analyze_data(); 81 | 82 | /* 83 | * Manipulate images, hide or visible 84 | */ 85 | 86 | if (!empty($options['hide_draws'])) { 87 | $this->ods_hide_draws($options['hide_draws']); 88 | } 89 | $this->ods_hide_draw_conditions(); 90 | 91 | break; 92 | case 'application/vnd.oasis.opendocument.text': 93 | echo "ODT!!!!!!!!!!!"; 94 | $this->odt_analyze(); 95 | break; 96 | } 97 | 98 | if (file_exists($out_file)) { 99 | //delete destination file if exists 100 | unlink($out_file); 101 | } 102 | 103 | //copy template to destinatoin 104 | copy($template_file, $out_file); 105 | $zip->open($out_file); 106 | 107 | $content = $this->dom->saveXml(); 108 | 109 | if (!empty($options['extract_content'])){ 110 | file_put_contents($out_file . '-content.xml', $content); 111 | } 112 | 113 | // 114 | 115 | $zip->addFromString('content.xml', $content); 116 | 117 | //styles.xml 118 | $this->dom->loadXML($zip->getFromName('styles.xml')); 119 | $zip->addFromString('styles.xml', $this->render_styles()); 120 | 121 | //add images 122 | if ( !empty($options['with_image_dir']) ){ 123 | if (is_dir($options['with_image_dir'])){ 124 | //var_dump($zip->getFromName('META-INF/manifest.xml')); 125 | $this->dom->loadXML($zip->getFromName('META-INF/manifest.xml')); 126 | 127 | $zip->addFromString('META-INF/manifest.xml', 128 | $this->write_manifest( 129 | $this->dir_to_zip( 130 | $zip, 131 | $options['with_image_dir'], 132 | 'Pictures') 133 | ) 134 | ); 135 | } 136 | } 137 | 138 | if (!empty($options['dom_stay'])){ 139 | $this->dom->loadXML($content); 140 | } 141 | 142 | //find unused images and and delete from zip 143 | 144 | $zip->close(); 145 | } 146 | 147 | function odt_analyze(){ 148 | $text = $this->dom->getElementsByTagName('text')->item(0); 149 | 150 | $para = $text->getElementsByTagName('p'); 151 | $this->odt_parse_elements($para); 152 | 153 | $para = $text->getElementsByTagName('h'); 154 | $this->odt_parse_elements($para); 155 | 156 | //images 157 | $this->ods_render_cell_images($text, $this->data); 158 | } 159 | 160 | function odt_parse_elements($elements){ 161 | foreach ($elements as $p){ 162 | foreach ($p->childNodes as $item){ 163 | $textContent = $item->textContent; 164 | if ($this->string_has_params($textContent)){ 165 | //echo "PARSE: \"$textContent\" -> "; 166 | $item->nodeValue = $this->parse_string($textContent, $this->data); 167 | //echo "\"" . $item->nodeValue . "\"\n"; 168 | } 169 | } 170 | } 171 | } 172 | 173 | function delete_from_manifest($filename){ 174 | $file_entries = $this->dom_elements2array( $this->dom->getElementsByTagName('file-entry') ); 175 | foreach ($file_entries as $file_entry){ 176 | if ( $file_entry->getAttribute('manifest:full-path') == $filename ){ 177 | $file_entry->parentNode->removeChildren( $file_entry ); 178 | } 179 | } 180 | } 181 | 182 | function write_manifest($files = array()){ 183 | $manifest = $this->dom->getElementsByTagName('manifest')->item(0); 184 | 185 | foreach ($files as $file){ 186 | $file_entry = $this->dom->createElement('manifest:file-entry'); 187 | 188 | $file_entry->setAttribute('manifest:full-path', $file['path']); 189 | $file_entry->setAttribute('manifest:media-type', $file['mime']); 190 | 191 | $manifest->appendChild($file_entry); 192 | } 193 | 194 | return $this->dom->saveXML(); 195 | } 196 | 197 | function read_meta() { 198 | $this->meta = array(); 199 | foreach ($this->dom->getElementsByTagName('user-defined') as $ud) { 200 | $pair = array( 201 | 'name' => $ud->getAttribute('meta:name'), 202 | 'value' => $ud->nodeValue, 203 | 'func' => 'unknown' 204 | ) 205 | ; 206 | 207 | if (strpos($pair['name'], 'SUM(') === 0) { 208 | $pair['func'] = 'sum'; 209 | list($one, $two) = explode('SUM(', $pair['name']); 210 | $prm_str = explode(')', $two); 211 | $params1 = explode(',', $prm_str[0]); 212 | $pair['params'] = array(); 213 | foreach ($params1 as $prm) { 214 | $param = ltrim(rtrim($prm)); 215 | if ($param) { 216 | $pair['params'][] = $param; 217 | } 218 | } 219 | } 220 | 221 | if (strpos($pair['name'], 'MAX(') === 0) { 222 | $pair['func'] = 'max'; 223 | list($one, $two) = explode('MAX(', $pair['name']); 224 | $prm_str = explode(')', $two); 225 | $params1 = explode(',', $prm_str[0]); 226 | $pair['params'] = array(); 227 | foreach ($params1 as $prm) { 228 | $param = ltrim(rtrim($prm)); 229 | if ($param) { 230 | $pair['params'][] = $param; 231 | } 232 | } 233 | } 234 | 235 | if (strpos($pair['name'], 'MIN(') === 0) { 236 | $pair['func'] = 'min'; 237 | list($one, $two) = explode('MIN(', $pair['name']); 238 | $prm_str = explode(')', $two); 239 | $params1 = explode(',', $prm_str[0]); 240 | $pair['params'] = array(); 241 | foreach ($params1 as $prm) { 242 | $param = ltrim(rtrim($prm)); 243 | if ($param) { 244 | $pair['params'][] = $param; 245 | } 246 | } 247 | } 248 | 249 | $this->meta[$ud->getAttribute('meta:name')] = $pair; 250 | } 251 | } 252 | 253 | function render_styles() { 254 | foreach ( 255 | $this->dom 256 | ->getElementsByTagName('master-styles')->item(0) 257 | ->getElementsByTagName('p') as $p) { 258 | $text = $p->nodeValue; 259 | 260 | if ($this->string_has_params($text)) { 261 | $p->nodeValue = $this->parse_string($text, $this->data); 262 | } 263 | } 264 | 265 | return $this->dom->saveXml(); 266 | } 267 | 268 | function ods_hide_draws($hide_draws) { 269 | $draws = $this->dom->getElementsByTagName('frame'); 270 | foreach ($draws as $draw) { 271 | if (in_array($draw->getAttribute('draw:name'), $hide_draws)) { 272 | $draw->parentNode->removeChild($draw); 273 | } 274 | } 275 | } 276 | 277 | /* 278 | analyze all draws and read descr conditions by data 279 | */ 280 | function ods_hide_draw_conditions() { 281 | $draws = $this->dom->getElementsByTagName('frame'); 282 | foreach ($draws as $draw) { 283 | $hide_image = false; 284 | 285 | $title = $draw->getElementsByTagName('title'); 286 | 287 | if ($title->length > 0 && $title->item(0)->nodeValue == 'conditions') { 288 | 289 | $desc = $draw->getElementsByTagName('desc'); 290 | if ($desc->length > 0 && $desc->item(0)->nodeValue) { 291 | $conditions = $desc->item(0)->nodeValue; 292 | 293 | $data = $this->data; 294 | $hide_image = eval("return " . $conditions . ";"); 295 | } 296 | } 297 | 298 | if ($hide_image) { 299 | $draw->parentNode->removeChild($draw); 300 | } 301 | } 302 | } 303 | 304 | function shell($commands = array()) { 305 | exec(join('; ', $commands), $out); 306 | return $out; 307 | } 308 | 309 | function ods_sheet($sheet_name) { 310 | 311 | $list = $this->dom->getElementsByTagName('table:table'); 312 | 313 | foreach ($list as $sheet) { 314 | 315 | if ( 316 | $sheet->getAttribute('table:name') == $sheet_name || 317 | $sheet->getAttribute('name') == $sheet_name || 318 | $sheet->getAttributeNS('table', 'name') == $sheet_name 319 | ) { 320 | return $sheet; 321 | } 322 | } 323 | return false; 324 | } 325 | 326 | function ods_sheet_add($sheet_name) { 327 | 328 | //create temporary sheet 329 | $sheet = $this->dom->createElement('table:table'); 330 | $sheet->setAttribute('table:name', $sheet_name); 331 | $sheet->setAttribute('name', $sheet_name); 332 | 333 | $this->dom 334 | ->getElementsByTagName('spreadsheet') 335 | ->item(0) 336 | ->appendChild($sheet); 337 | 338 | return $sheet; 339 | } 340 | 341 | function ods_debug($title, $value = '') { 342 | 343 | $row = $this->dom->createElement('table:table-row'); 344 | 345 | $p1 = $this->dom->createElement('text:p'); 346 | $p2 = $this->dom->createElement('text:p'); 347 | $p1->nodeValue = $title; 348 | $p2->nodeValue = $value; 349 | 350 | $cell1 = $this->dom->createElement('table:table-cell'); 351 | $cell2 = $this->dom->createElement('table:table-cell'); 352 | 353 | $cell1->appendChild($p1); 354 | $cell2->appendChild($p2); 355 | 356 | $row->appendChild($cell1); 357 | $row->appendChild($cell2); 358 | 359 | $this->ods_sheet('DEBUG')->appendChild($row); 360 | } 361 | 362 | /* 363 | * return ranges with level=1 364 | */ 365 | function ods_level1_ranges() { 366 | $level0ranges = array(); 367 | 368 | foreach ($this->schema['named-range'] as $range_name => $range){ 369 | if ($range['level'] == 1){ 370 | $level0ranges[] = $range_name; 371 | } 372 | } 373 | 374 | return $level0ranges; 375 | } 376 | 377 | function ods_analyze_ranges() { 378 | $nlist = array(); 379 | 380 | foreach ($this->dom->getElementsByTagName('named-range') as $named) { 381 | $range_id = 'range' . $this->last_id++; 382 | 383 | $named->setAttribute('id', $range_id); 384 | 385 | $range = compact('range_id') + array( 386 | 'name' => 387 | $named->getAttribute('table:name'), 388 | 'id' => $range_id, 389 | 'cell-range-address' => 390 | $named->getAttribute('table:cell-range-address'), 391 | 'range-usable-as' => 392 | explode(' ', $named->getAttribute('table:range-usable-as')), 393 | ); 394 | 395 | list($sh, $start, $end) = explode( 396 | '.$', str_replace( 397 | ':', '', $range['cell-range-address']) 398 | ); 399 | 400 | list($tmp, $range['start']) = explode('$', $start); 401 | list($tmp, $range['end']) = explode('$', $end); 402 | list($tmp, $range['sheet']) = explode('$', $sh); 403 | 404 | $range['length'] = $range['end'] - $range['start'] + 1; 405 | 406 | $range['children'] = array(); 407 | $range['parent'] = null; 408 | $range['template_rows'] = array(); //Array of row elements 409 | 410 | //repeat-row only 411 | if (in_array('repeat-row', $range['range-usable-as'])){ 412 | $nlist[$range['start']] = $range; 413 | } 414 | } 415 | 416 | //Sort ranges 417 | ksort($nlist); 418 | 419 | foreach ($nlist as $nkey => $n) { 420 | $this->schema['named-range'][$n['name']] = $n; 421 | } 422 | 423 | 424 | /* 425 | * counting level1 ranges 426 | */ 427 | 428 | foreach ($this->schema['named-range'] as $range_name => $range){ 429 | if (array_key_exists($range_name, $this->data) ){ 430 | $this->data[ "COUNT($range_name)" ] = count( $this->data[ $range_name ] ); 431 | 432 | 433 | } 434 | 435 | $this->data += $this->ods_aggregate_data($range_name, $this->data); 436 | } 437 | } 438 | 439 | function ods_analyze_images() { 440 | $this->dom->getElementsByTagName('table')->item(0) 441 | ->getElementsByTagName(''); 442 | } 443 | 444 | function ods_analyze_row_ranges($row) { 445 | 446 | $row_ranges = $this->row_ranges($row->getAttribute('number')); 447 | 448 | if ($row_ranges) { 449 | 450 | $from = $row->getAttribute('from'); 451 | 452 | //analyze ranges with parent<>child 453 | $level = count($row_ranges); 454 | 455 | $last_row_range = end($row_ranges); 456 | 457 | $row->setAttribute('range_name', $last_row_range); 458 | $row->setAttribute('range_level', $level); 459 | 460 | if ($from == $this->schema['named-range'][$last_row_range]['start']) { 461 | $row->setAttribute('range_start', $last_row_range); 462 | } 463 | 464 | $end_ranges = array(); 465 | 466 | foreach ($this->schema['named-range'] as $tmprange) { 467 | if ($from == $tmprange['end']) { 468 | $end_ranges[] = $tmprange['name']; 469 | } 470 | } 471 | 472 | if ($end_ranges) { 473 | $row->setAttribute('range_end', join(',', $end_ranges)); 474 | } 475 | 476 | //Insert all used ranges 477 | $row->setAttribute('ranges', join(',', $row_ranges)); 478 | 479 | $this->schema['named-range'][$last_row_range]['level'] = $level; 480 | if ($level > 1) { 481 | $range_parent = $row_ranges[$level - 2]; 482 | $this->schema['named-range'] 483 | [$last_row_range] 484 | ['parent'] = $range_parent; 485 | 486 | $row->setAttribute('range_parent', $range_parent); 487 | $this->schema['named-range'] 488 | [$range_parent] 489 | ['children'] 490 | [$last_row_range] = $last_row_range; 491 | 492 | } else { 493 | 494 | $this->schema['named-range'][$last_row_range]['parent'] = null; 495 | } 496 | 497 | 498 | foreach ($this->schema['named-range'] as $tmprange) { 499 | if (in_array($tmprange['name'], $row_ranges)) { 500 | $this->schema['named-range'] 501 | [$tmprange['name']] 502 | ['template_rows'] 503 | [] = $row; 504 | //$this->dom->saveXml($row); 505 | } 506 | } 507 | 508 | //analyze virtualFields, in office:annotations 509 | $office_annotationa = $row->getElementsByTagName('annotation'); 510 | if ($office_annotationa->length > 0) { 511 | $office_annotationa = $this->dom_elements2array($office_annotationa); 512 | foreach ($office_annotationa as $item){ 513 | $p = $item->getElementsByTagName('p')->item(0); 514 | $expression = $p->nodeValue; 515 | 516 | $fieldName = $item->parentNode->lastChild->nodeValue; //->firstChild->nodeValue; 517 | $expr = $this->ods_is_string_expression($expression) 518 | ? 'true' : 'false'; 519 | //print_r(compact('expression', 'fieldName', 'expr')); 520 | 521 | if ($this->ods_is_string_expression($expression)){ 522 | $this->schema['named-range'] 523 | [ $last_row_range ] 524 | ['virtualFields'] 525 | [ $fieldName ] = 526 | $expression; 527 | 528 | $item->parentNode->removeChild($item); 529 | } 530 | 531 | } 532 | } 533 | } //if $row_nages 534 | 535 | return $row_ranges; 536 | } 537 | 538 | //http://ru.stackoverflow.com/questions/454598/%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5 539 | //http://stackoverflow.com/questions/18880772/calculate-math-expression-from-a-string-using-eval 540 | private function parse_string_expression($string, $data = array()){ 541 | 542 | $string1 = $this->parse_string($string, $data); 543 | 544 | /* 545 | * check is string is contains ONLY DIGITS and 546 | * operations!, and not contain not parsed [param] strings parts 547 | */ 548 | 549 | try { 550 | $newfunc = create_function('', "return $string1;"); 551 | $val = $newfunc(); 552 | unset($newfunc); 553 | return $val; 554 | 555 | } catch (Exception $exc) { 556 | //echo $exc->getTraceAsString(); 557 | //function error 558 | return "#ERROR"; 559 | } 560 | } 561 | 562 | /* 563 | * "[Good.price] * [Good.count]" is ok 564 | */ 565 | private function ods_is_string_expression($string){ 566 | $string = str_replace(array( 567 | ' ', 568 | '+', 569 | '-', 570 | '*', 571 | '/', 572 | '(', 573 | ')' 574 | ), array( 575 | '', 576 | '