├── .gitattributes ├── LICENSE ├── README.md ├── examples ├── A large text - if You like to include it in the document.txt ├── APEX_app.sql ├── An image - if You like to include it in the document.png └── p_create_word.sql ├── package ├── ZT_WORD.pkb └── ZT_WORD.pks └── preview.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zoran Tica 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Oracle PL/SQL API for Microsoft Word DocX Documents Generation 2 | Microsoft Word Documents API provides functionality to quickly and efficiently generate Microsoft Word Documents (DOCX) directly from Oracle database. 3 | 4 | It requires no additional resources and it is developed in pure PL/SQL. 5 | 6 | ## Changelog 7 | - 1.0 - Initial Release 8 | - 2.0 - Images; table borders 9 | - 2.1 - Default spelling and grammar language 10 | - 2.11 - Fixed special characters issue 11 | - 2.2 - Draw a table in the header or footer 12 | - 2.3 - Newline in a paragraph support 13 | - 2.4 - Large text (clob) in a paragraph 14 | 15 | ## Install 16 | - download 2 script files from "package" folder 17 | - execute them in database schema in following order: 18 | 1. PKS script file (package definition) 19 | 2. PKB file (package body) 20 | 21 | New Package ZT_WORD is created in database schema. 22 | 23 | ## How to use 24 | A script with examples is available in "examples" folder. Strongly recommended to try it first. 25 | 26 | ## Examples 27 | Examples are wrapped up in a database procedure named p_create_word and it's source can be located in the "examples" folder (file p_create_word.sql). 28 | 29 | Optionally there is an APEX application which You may use as a GUI. It can be also located in the examples folder (file APEX_app.sql, APEX 19.2 or newer required). 30 | 31 | *A remark: If You want to download the file from the APEX app then uncomment the line of code "apex_application.stop_apex_engine;" in the package body (procedure p_download_document). Otherwise the download won't work.* 32 | 33 | ## Demo Application 34 | https://apex.oracle.com/pls/apex/f?p=zttechdemo 35 | 36 | ![](https://github.com/zorantica/plsql-word/blob/master/preview.png) 37 | -------------------------------------------------------------------------------- /examples/A large text - if You like to include it in the document.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus efficitur id risus sit amet ultricies. Duis sed nunc eget elit porta sagittis sit amet ut lorem. Morbi sollicitudin libero non eros dapibus, id ultricies ante tincidunt. Vestibulum egestas, lectus a maximus semper, tortor orci maximus ipsum, id bibendum diam magna eget odio. Nunc nec metus nec felis malesuada tincidunt at vitae turpis. Nulla eget nunc in risus elementum bibendum vitae non ipsum. Aliquam sit amet nulla efficitur ex ultrices luctus quis vel tortor. Nunc sed tincidunt quam, in pretium nunc. Nullam felis nulla, pharetra eget ipsum ac, rutrum scelerisque ex. Cras neque libero, pellentesque vitae lectus in, iaculis tincidunt erat. Pellentesque urna elit, rutrum vitae neque sit amet, lobortis feugiat ante. Donec ut tempor diam. Aenean non lorem a purus mollis gravida. Praesent pellentesque dolor et felis pretium, ut tristique dolor tincidunt. In hendrerit eros vel ligula dignissim rhoncus. 2 | 3 | Nulla cursus libero ac velit semper dapibus. Integer mi dolor, semper in ornare in, iaculis sed neque. Nunc pulvinar, arcu vel sollicitudin egestas, enim enim euismod erat, viverra efficitur nisi magna et tortor. Proin auctor mollis ullamcorper. Maecenas rutrum efficitur eros a rhoncus. Suspendisse ac dolor vel nisi sagittis consectetur. Morbi bibendum rutrum ante, eu pretium tortor volutpat et. 4 | 5 | Morbi tincidunt porta lorem ut dignissim. Quisque vitae sem sem. Curabitur sit amet felis ullamcorper, tristique nunc quis, consequat leo. Cras iaculis tortor sit amet mi efficitur, ut consectetur erat egestas. Quisque blandit ullamcorper lectus, sed lacinia tellus. In venenatis in arcu in suscipit. Aenean bibendum ante urna, ut sollicitudin erat tincidunt id. In viverra egestas lacus, nec aliquam massa lobortis sed. Sed ultricies mauris non mi feugiat blandit. Nulla facilisi. Sed eu sapien nulla. Etiam rutrum enim ipsum, non mattis orci lobortis id. Nulla ac turpis non justo semper aliquet. Integer feugiat efficitur felis, vitae vulputate ipsum iaculis at. Curabitur feugiat, tortor in interdum tristique, eros sem consequat tellus, vitae aliquet est purus quis felis. Aenean in quam sagittis, dignissim tortor sed, vestibulum purus. 6 | 7 | Nam vel convallis justo. Phasellus ultricies dictum laoreet. Nam id feugiat dui, non sagittis dolor. Ut sed pellentesque tellus. Morbi mauris ipsum, vestibulum vel lacus sed, posuere elementum mi. Nulla in ligula luctus, mollis tellus non, pharetra mauris. Suspendisse sit amet lacus nibh. Vestibulum eu nunc enim. Maecenas commodo sollicitudin eros tempus euismod. Donec ac urna nec dolor tempus rhoncus. Nam varius luctus eros sed aliquam. Duis vitae rhoncus enim. Curabitur sed eros at lorem ultrices ultricies. 8 | 9 | Ut rutrum odio ut tortor malesuada, ut accumsan ex rutrum. Pellentesque tempus, lorem quis finibus convallis, ex libero pellentesque massa, dignissim pretium ipsum sem eget ante. Curabitur sed tincidunt nunc. Nullam eget risus id nunc dictum condimentum ut sit amet lacus. Curabitur egestas sit amet tortor sed sagittis. Morbi fringilla condimentum enim. Pellentesque fermentum a ante nec lobortis. Nunc id posuere augue, vel ultricies urna. Duis et neque nisl. Suspendisse condimentum tempus lorem, non maximus enim gravida ut. Donec ut gravida lorem. Sed facilisis, justo vel congue mollis, purus eros sollicitudin est, ac dignissim est velit quis odio. Proin in suscipit felis, non porttitor lacus. Praesent eu sollicitudin dolor, nec laoreet dui. In sit amet cursus neque, in luctus est. 10 | 11 | Proin turpis nunc, interdum a gravida eget, elementum sit amet augue. In at elit non tellus ullamcorper feugiat. Nunc non tincidunt mi. Donec dapibus lectus eget magna vehicula, id tincidunt erat mollis. Suspendisse viverra nisi sed congue egestas. Integer ac vehicula dolor. Fusce sit amet pharetra lacus. Donec et ipsum elementum, facilisis sapien vitae, vestibulum mi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi at ullamcorper ipsum. Morbi ultrices leo ex. In luctus urna eget sapien fermentum, vitae placerat libero mollis. Maecenas eleifend, ligula at malesuada lobortis, elit sem feugiat mi, ac sagittis nisl quam eget elit. Donec a nibh arcu. 12 | 13 | Mauris placerat odio a pulvinar accumsan. Cras ullamcorper tempor massa nec semper. Praesent ornare tempus nisi. Nunc mi quam, sodales eget nulla feugiat, tincidunt ullamcorper nunc. Mauris accumsan euismod sem ac accumsan. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent gravida mauris quis vulputate auctor. Cras ac consequat ipsum, ac laoreet lacus. Cras sed porttitor mauris. 14 | 15 | Aenean pulvinar ligula a magna commodo, eget porta turpis mollis. Aenean ac felis lacinia, aliquet sem at, hendrerit ex. Quisque condimentum mi vel purus tempor dapibus. Duis at hendrerit elit, at volutpat orci. Integer sem sapien, luctus in magna vel, consequat volutpat velit. Morbi consectetur mi eget commodo maximus. Cras ornare, nisi sit amet suscipit pellentesque, sem urna venenatis orci, at molestie tellus libero vel tellus. Morbi enim orci, consequat ut velit quis, ultrices bibendum augue. Nulla facilisi. 16 | 17 | Sed vel porttitor enim, vitae auctor libero. Aliquam viverra magna at tempor efficitur. Ut finibus vitae quam a pretium. Mauris eros odio, accumsan id est accumsan, viverra egestas nisi. Aenean vitae est diam. Nulla elit turpis, finibus quis nulla sed, scelerisque tempor diam. Mauris pretium euismod eleifend. 18 | 19 | Cras est justo, tincidunt a tristique quis, scelerisque consequat ligula. Phasellus interdum leo a metus eleifend egestas ut nec enim. Morbi ut fringilla elit, non fermentum quam. Vivamus rhoncus eleifend dui sed egestas. Aliquam aliquam diam nulla, eu vehicula dolor pharetra ac. Sed eu imperdiet urna. Morbi placerat pulvinar suscipit. Sed imperdiet quis nisl in ornare. Quisque sagittis venenatis porttitor. Praesent nec dui a odio viverra dapibus. Sed eu orci a turpis tempor congue vitae non tortor. Vestibulum non tincidunt lectus. 20 | 21 | Morbi facilisis luctus mi, ac eleifend nisi condimentum at. Duis bibendum libero odio, eu rutrum sem hendrerit sed. In commodo nulla tellus, eu mattis elit aliquam ac. In sollicitudin lacus massa, id feugiat lorem tempor sed. Nullam quis efficitur nisl. Vestibulum aliquet ex libero. Nullam id nibh nec nisi efficitur condimentum at rutrum mi. Nullam vel odio vulputate, dignissim nunc dignissim, maximus velit. 22 | 23 | Curabitur congue magna sit amet dignissim aliquam. Nulla quis tempus risus, at tempor mauris. Vestibulum a erat et est bibendum auctor. Morbi interdum ultrices nibh, vel pretium purus commodo eu. Nam non faucibus elit. Ut elementum augue et orci viverra, vitae consequat diam ultrices. Maecenas eget diam id nulla dictum sollicitudin sed sed felis. Nulla luctus magna augue, in euismod neque aliquet pulvinar. Nullam at elit nec mi dapibus pharetra. Nam tincidunt nunc eu urna posuere interdum. Proin rutrum a nunc sit amet pellentesque. Nam a ullamcorper nisl. Praesent lobortis enim quis tortor ultricies placerat. Pellentesque erat neque, condimentum at magna quis, eleifend semper ligula. 24 | 25 | Suspendisse egestas molestie pulvinar. Cras in molestie purus, a rutrum urna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam et pulvinar lorem, in porta eros. Suspendisse potenti. Duis ut commodo nibh. Ut nec turpis et ligula vestibulum rutrum. Quisque non turpis quis purus condimentum congue. 26 | 27 | Integer congue scelerisque nunc, ut aliquam ex sodales euismod. Nulla tristique arcu tempor ligula imperdiet, at dapibus velit dapibus. Proin nisi orci, malesuada sed ullamcorper ac, varius iaculis leo. Duis non tristique lorem. Fusce pharetra arcu enim, ac tincidunt tortor ultricies at. Aenean feugiat lorem nulla. Ut et diam sed nisi molestie commodo sit amet vitae augue. Suspendisse laoreet ex eu nisl rutrum vehicula at ut ligula. Donec in dapibus nunc. Quisque eleifend neque magna, id rhoncus est hendrerit et. In posuere rutrum velit, vitae dignissim dolor. Nunc nunc dui, suscipit auctor lobortis vel, lobortis sit amet urna. Praesent congue nisi nec nibh pretium dictum. 28 | 29 | Nunc commodo lectus non justo tempor interdum. Vestibulum pulvinar turpis arcu, semper volutpat felis eleifend sed. Sed euismod vehicula turpis, vel congue neque ornare nec. In porta augue leo, non dignissim libero vestibulum et. Vivamus sagittis id augue eu mollis. Proin dui diam, ultrices sed sodales iaculis, efficitur id turpis. Duis eget dolor porta diam tincidunt tincidunt sit amet non metus. Morbi justo nibh, convallis hendrerit tincidunt vitae, consequat vitae quam. Cras maximus iaculis diam. Donec vel nibh eget felis maximus aliquam. Cras interdum turpis ut consequat blandit. 30 | 31 | Nulla sit amet erat lacus. Morbi sit amet arcu et nunc ultrices iaculis. Aenean rhoncus gravida tortor imperdiet accumsan. Vestibulum quis mi quis leo gravida dictum. Mauris sit amet dolor tempus, laoreet eros eu, elementum libero. In vel tempor diam. Nulla facilisi. Donec molestie aliquam elit vel mattis. 32 | 33 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi tortor sapien, vehicula sit amet mollis in, luctus vitae dui. Vivamus lorem ante, viverra vel cursus vitae, fermentum vel nunc. Maecenas nec ipsum in mauris mollis dignissim. In rhoncus erat quis arcu fringilla gravida. Nullam semper rutrum vulputate. Pellentesque nisl neque, imperdiet et convallis sit amet, posuere id ex. Duis ut faucibus lectus. Nam maximus libero tincidunt, fermentum purus eget, cursus risus. Proin id tempor nibh. Duis ut felis a leo malesuada condimentum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque quis vulputate lectus. Pellentesque lectus leo, egestas vitae pharetra a, rhoncus at urna. 34 | 35 | Duis in turpis pharetra, pharetra ligula vel, euismod neque. Donec luctus sem a interdum pharetra. Vestibulum quis pretium quam. Nulla gravida, ante sed volutpat eleifend, purus justo viverra urna, vitae pulvinar eros sem sed tortor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Proin eget odio faucibus, iaculis turpis nec, volutpat nulla. Maecenas vel metus eu sapien fermentum hendrerit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis id turpis tellus. Phasellus vulputate, leo id tempor rhoncus, ligula velit varius ex, ac cursus tortor turpis vitae justo. In tristique neque in leo ultrices tempor. Aenean quis convallis risus, ut tempus risus. Etiam metus nisi, dictum at augue ac, molestie varius lectus. Nullam blandit laoreet libero id condimentum. In leo enim, eleifend quis ex at, finibus bibendum sapien. Donec efficitur metus in tellus tempus commodo. 36 | 37 | Sed convallis neque eget mauris facilisis, quis feugiat enim suscipit. Nulla ipsum libero, tempor in lacus aliquam, rhoncus lacinia mi. Ut ornare euismod justo, viverra aliquam libero mattis eget. Mauris tristique convallis nisl, vel finibus turpis aliquam eget. Praesent convallis ullamcorper erat, ac aliquet arcu iaculis eget. Sed vulputate, dolor eget semper facilisis, magna purus feugiat orci, ut mollis turpis justo a purus. Donec scelerisque eleifend lobortis. Sed facilisis et justo ac pretium. Quisque maximus vel urna sed lobortis. Proin ultrices condimentum lacus, sed accumsan eros condimentum ut. Nulla pharetra felis eget feugiat interdum. Nullam ac cursus nunc, sed hendrerit leo. Morbi vel viverra neque. Proin fermentum vestibulum aliquam. 38 | 39 | Cras mi enim, faucibus at ante a, eleifend ullamcorper mi. Nunc vitae dolor bibendum, volutpat massa et, semper quam. Aenean maximus ante in suscipit tristique. Nullam ornare dignissim leo ut commodo. Mauris sit amet velit euismod, suscipit magna vitae, vulputate odio. Pellentesque imperdiet, elit vel tincidunt fringilla, sapien nulla elementum sapien, eget fringilla dui libero eget mauris. Aenean vel magna ornare, convallis libero ac, pretium tortor. 40 | 41 | Nulla in bibendum risus. Nulla pretium, enim ac imperdiet blandit, nibh felis imperdiet justo, sit amet pharetra enim ligula ut nisl. Morbi ut convallis elit. Ut varius sagittis arcu. Pellentesque volutpat, urna vel rhoncus varius, arcu ligula euismod eros, sed dictum nisi ligula a erat. Cras sollicitudin ultrices pellentesque. Mauris vel venenatis risus, tempus tincidunt arcu. Pellentesque sapien leo, iaculis id efficitur id, vestibulum sit amet sem. Phasellus commodo, nisl et consectetur luctus, mi libero posuere est, eu tempor purus quam pulvinar massa. Donec sagittis ex ut velit congue, ut venenatis arcu sodales. Praesent varius sem sed metus pharetra porttitor. Etiam finibus turpis mauris, ac varius justo tincidunt mollis. Phasellus fermentum, lacus ut aliquet finibus, nisi velit suscipit orci, in ultrices lectus tellus cursus ex. Phasellus cursus lobortis nisi id iaculis. Ut sed lectus eget risus laoreet scelerisque. 42 | 43 | Suspendisse vehicula lacus sed sapien mattis, non mollis mauris tincidunt. Nulla tempus varius turpis, non molestie metus condimentum a. Pellentesque mi mi, tempus ac mollis et, bibendum eu arcu. Vestibulum faucibus diam volutpat, viverra leo eleifend, ultrices quam. Integer eget convallis sapien. Nulla non tortor tortor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Fusce efficitur euismod eros, vitae faucibus est varius sed. Cras in metus in magna tempor laoreet. Nunc consequat molestie ante consequat posuere. Sed laoreet fermentum ex, ut finibus eros facilisis a. Suspendisse sit amet nunc eget tortor vestibulum vestibulum at id augue. Cras id neque vitae velit cursus sodales. Donec pretium lorem id ipsum dapibus imperdiet. 44 | 45 | Donec sit amet quam at eros pretium feugiat. Sed erat neque, vulputate sodales neque quis, vehicula hendrerit nunc. Cras id magna eget ante vestibulum bibendum eu non ante. Morbi ante orci, elementum et sapien non, interdum scelerisque nunc. Ut fermentum vehicula consectetur. Phasellus at sollicitudin tellus, a gravida arcu. Vestibulum a ultricies lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec dui justo, placerat sit amet semper ac, dapibus sit amet metus. Sed porta vestibulum varius. 46 | 47 | Nam vulputate dolor odio, sed ultricies diam eleifend sed. Nunc non convallis velit, non ullamcorper nibh. Donec in urna et quam cursus cursus a et justo. Nunc sagittis, lectus a feugiat ullamcorper, massa odio tristique libero, sed luctus dolor justo ac diam. Suspendisse sit amet libero mi. Cras euismod faucibus est vitae porta. Phasellus id lacinia orci. Aenean finibus arcu id sollicitudin luctus. Suspendisse mattis porta purus non malesuada. Phasellus aliquet condimentum auctor. Quisque tempor est tortor, nec eleifend mauris feugiat nec. Sed a pulvinar orci, a efficitur nisl. 48 | 49 | Pellentesque egestas, purus sed placerat euismod, nibh nisi iaculis tellus, eget suscipit felis metus ac nisl. In quis tristique nunc. Vivamus pharetra mauris magna, at posuere odio tincidunt quis. Nulla feugiat id quam in finibus. Aliquam condimentum luctus enim, a sollicitudin sapien accumsan a. Suspendisse blandit molestie ex, non iaculis nulla vehicula non. Pellentesque mattis, enim ut sodales viverra, leo neque eleifend lorem, ut tristique nunc leo in neque. Integer pulvinar iaculis libero in euismod. Aenean ultricies metus nec enim commodo, id finibus tortor tristique. Pellentesque sit amet tempor metus, quis varius mi. Etiam in sapien vel libero finibus placerat nec et nulla. In nec odio leo. Ut non tortor quis quam condimentum congue et non dui. 50 | 51 | Praesent lacinia justo et neque placerat, non dignissim est ullamcorper. Suspendisse non lacus laoreet, feugiat magna at, tincidunt ante. Donec quis massa eu lacus ultricies malesuada in a ligula. Pellentesque et erat at mauris cursus congue. Phasellus tincidunt ex dolor. Sed velit dolor, consequat non est id, tristique bibendum felis. Aenean vitae elementum nunc, vel tristique dolor. Duis mattis non mi quis iaculis. Fusce condimentum purus a ante porttitor, sit amet vulputate dolor tristique. Donec scelerisque, arcu lacinia lobortis venenatis, ante ipsum elementum sem, vehicula laoreet justo ligula id justo. Fusce eget tellus a dolor tempus dapibus quis eu lectus. Nam rhoncus lectus orci, ut eleifend ante cursus nec. Ut non augue at nunc facilisis rhoncus. 52 | 53 | Nullam elit risus, sollicitudin sed felis sed, tincidunt blandit tellus. Pellentesque porta justo ut magna tempor accumsan. Vivamus facilisis ante nec hendrerit pharetra. Vestibulum varius et elit non congue. Maecenas neque libero, tempus et tortor a, tempor convallis arcu. Curabitur et ex rutrum, iaculis erat et, tristique libero. Phasellus porta in turpis ut dictum. Duis hendrerit finibus risus, et porta mauris vestibulum eu. Vestibulum sagittis augue sit amet enim consequat, vitae imperdiet ipsum tincidunt. Proin tempor consequat orci, vitae rhoncus felis. Pellentesque eleifend felis sed massa dignissim, quis finibus quam aliquam. Nulla vel tellus ac nibh commodo congue sed eu sapien. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus pretium luctus interdum. 54 | 55 | Suspendisse convallis vel dui et fermentum. Suspendisse diam lectus, laoreet et ligula nec, dictum interdum nisi. Pellentesque ut nunc tortor. Praesent eleifend faucibus accumsan. Cras faucibus venenatis est, et maximus odio pellentesque ac. Suspendisse sit amet quam sed dolor faucibus cursus at eget magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. 56 | 57 | Nam mattis urna vel quam eleifend, vel tempus nunc pellentesque. Fusce non orci lacinia, bibendum diam venenatis, auctor sem. Vestibulum et pellentesque purus. Mauris porttitor nunc nec justo scelerisque tempor. In sit amet leo dolor. Donec luctus hendrerit velit. Aenean rutrum egestas feugiat. 58 | 59 | Aliquam sem turpis, malesuada id quam quis, pulvinar aliquam tellus. Maecenas tempor vel justo sed suscipit. Phasellus sed nisl est. Pellentesque dignissim viverra faucibus. Morbi efficitur urna vel leo egestas, fermentum auctor neque eleifend. Nam porttitor porttitor neque ac viverra. Praesent aliquam eget eros a convallis. Donec quis turpis efficitur, porttitor mauris tempus, accumsan enim. In pellentesque pharetra arcu, nec pellentesque enim faucibus vitae. Nullam posuere arcu eros, eget ultricies odio ullamcorper non. Vivamus tempor ac sapien vel porta. Praesent tincidunt placerat leo. Maecenas quis nibh tincidunt turpis molestie molestie. Suspendisse consectetur quis dolor nec ultrices. Nam posuere auctor gravida. 60 | 61 | Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Proin cursus metus libero, lobortis viverra turpis tristique in. Quisque pulvinar efficitur nibh, at maximus dui fringilla et. Vivamus rutrum id felis venenatis varius. Sed venenatis, neque eu consectetur finibus, enim felis sodales sapien, ac feugiat metus mauris nec est. Etiam gravida felis risus, vitae luctus massa pellentesque quis. Nulla egestas nunc ac sem consectetur, sit amet iaculis nunc euismod. Curabitur congue dui eu imperdiet commodo. Phasellus bibendum sit amet nulla tempus dictum. Suspendisse suscipit, urna sit amet pretium tempus, augue urna luctus eros, ut iaculis velit magna vel quam. 62 | 63 | Praesent mauris est, posuere at condimentum et, laoreet id augue. Maecenas quis efficitur sapien, a laoreet lectus. Maecenas augue dui, fermentum id libero in, auctor laoreet urna. Sed non ultrices enim. Quisque dignissim vitae sapien ut hendrerit. Fusce sed iaculis lectus. Curabitur in efficitur elit. Aenean mattis purus nec velit malesuada convallis ut nec augue. Vivamus tincidunt mi in elit molestie pretium. Cras venenatis lacinia orci. Praesent nec aliquam diam, vitae luctus felis. Quisque ac dapibus nibh, sed sollicitudin nunc. Aliquam auctor, massa ac aliquet dictum, purus nisi scelerisque justo, ut tincidunt tortor odio sit amet ante. Ut eget dui euismod, efficitur elit vitae, iaculis lectus. 64 | 65 | Suspendisse tincidunt suscipit rhoncus. Etiam porttitor volutpat convallis. Vestibulum id ipsum et nibh malesuada gravida. Suspendisse gravida tincidunt sodales. Ut imperdiet malesuada imperdiet. Sed nec diam orci. Mauris ullamcorper odio dictum orci ultricies varius. Praesent euismod, diam vel auctor eleifend, eros urna consequat ligula, id viverra velit risus nec neque. Integer a dignissim ipsum. Donec sagittis convallis lobortis. Mauris nec risus ut quam placerat mattis id in ex. Sed consequat eget eros quis gravida. Mauris ullamcorper tempor justo vel tristique. Donec quis ipsum varius sapien posuere dignissim. 66 | 67 | Pellentesque vestibulum urna quis eros scelerisque, id maximus justo ultrices. Pellentesque cursus justo non est rhoncus scelerisque. Ut non lorem ac turpis ultrices interdum. Vivamus condimentum blandit sem a sollicitudin. Pellentesque maximus rhoncus facilisis. Quisque bibendum ligula nec sagittis commodo. Nulla ut arcu fermentum, pharetra lorem at, auctor velit. Praesent fringilla dictum nisl vitae molestie. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam bibendum a ligula sed congue. Cras non mauris a augue dapibus pellentesque vel a velit. Nullam id arcu et augue gravida pellentesque. Quisque ac sapien in mauris fermentum laoreet. 68 | 69 | Praesent enim libero, elementum vel efficitur vitae, vehicula in eros. Donec ornare aliquam orci sed condimentum. Nulla bibendum, tellus in consectetur porttitor, nibh arcu lacinia neque, non consequat elit velit a elit. Sed varius, massa quis luctus cursus, libero diam eleifend leo, vitae consectetur orci augue nec purus. In hac habitasse platea dictumst. Fusce vel mi ac lacus convallis mollis. Nam eu interdum quam. Duis est elit, posuere in ante vel, gravida vehicula turpis. 70 | 71 | Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam sodales sodales nulla porttitor vulputate. Donec quam erat, euismod varius vehicula eget, sodales a metus. Aliquam erat volutpat. Etiam tincidunt risus mattis nulla finibus, quis molestie leo porttitor. Aliquam ac tincidunt dolor, ut blandit sem. Aenean finibus lobortis vestibulum. 72 | 73 | Nam at tristique risus. Maecenas ac suscipit nisi. Duis cursus lacus nec quam convallis lacinia in id risus. Aenean libero tellus, condimentum quis magna in, feugiat ultrices ligula. Etiam at fermentum ligula. Aenean eleifend rutrum aliquam. Nunc quis libero ornare, tincidunt turpis sit amet, euismod velit. Morbi quis dui commodo, euismod neque non, scelerisque massa. Praesent faucibus arcu et metus porttitor, in ultricies nulla mattis. Nunc sit amet justo nec ipsum condimentum imperdiet eu faucibus odio. Aenean gravida mattis est. Sed in blandit ipsum. Donec nec scelerisque ex. Etiam congue pellentesque sem, a venenatis massa imperdiet id. Integer eros tortor, auctor vitae est vel, aliquam eleifend sapien. Phasellus tincidunt dolor ante, eget scelerisque lorem luctus non. 74 | 75 | Etiam nec consectetur nisi, ac egestas ipsum. Integer facilisis placerat dapibus. Donec ultricies, augue non faucibus rutrum, ligula elit ullamcorper ante, non varius magna lorem a quam. Quisque non mauris et dolor sagittis sollicitudin. Nulla dapibus, tellus nec elementum posuere, nunc dolor fermentum arcu, sit amet dictum urna magna sit amet justo. Nulla mollis vitae libero eu pulvinar. In hac habitasse platea dictumst. Nullam eget sem eget urna consequat consequat. Nullam lobortis quis ex id aliquet. Vestibulum nibh sem, ornare eget sapien a, accumsan mollis odio. Phasellus accumsan varius augue, dapibus placerat ipsum porta vitae. Mauris quis dolor consectetur, pellentesque felis sit amet, commodo lorem. 76 | 77 | Maecenas eget orci at leo hendrerit vehicula. Donec rutrum mollis efficitur. Phasellus facilisis feugiat sapien eget imperdiet. Ut eget mollis odio. Nam ut pulvinar nunc. Sed scelerisque magna eu diam sagittis, id pulvinar ligula cursus. Duis eleifend dapibus mi vel ullamcorper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. 78 | 79 | Praesent quis finibus magna. Duis laoreet consequat orci, sed gravida nisi sagittis vel. Duis vitae ex consequat massa mattis maximus. Quisque sagittis commodo tincidunt. Integer in velit et ante hendrerit semper. Etiam porta bibendum bibendum. Curabitur suscipit libero ac augue tempus, sed feugiat metus vehicula. Praesent quis arcu consectetur, posuere libero quis, porttitor elit. 80 | 81 | Nam finibus faucibus fermentum. Pellentesque ultrices tempor orci nec tempus. Proin blandit nec tortor vel dapibus. Nam dapibus accumsan erat, ac mollis arcu varius porta. Mauris ac sem eget lectus elementum condimentum. Pellentesque metus orci, finibus quis augue non, luctus aliquet urna. Nam commodo ultricies elit vel porttitor. Donec convallis, ex eu dapibus interdum, urna lorem efficitur purus, eget tempor magna augue a elit. Phasellus pharetra enim in lacinia mollis. 82 | 83 | Nam scelerisque commodo nisi, at lobortis tellus bibendum quis. Ut elementum enim sed ligula laoreet ultrices. Duis facilisis nibh vitae lacus elementum, non facilisis elit fringilla. Phasellus id fringilla nunc, vel tempus augue. Cras porttitor massa ac aliquet tincidunt. Integer consectetur elit bibendum ultricies molestie. Proin aliquet id nisl nec fermentum. Nam euismod nisl suscipit, mollis velit non, sagittis mi. Sed sit amet felis quis mi viverra porttitor. 84 | 85 | In hac habitasse platea dictumst. Vivamus in dolor sit amet lacus pellentesque molestie. In nec orci congue, congue tellus et, interdum diam. Sed rhoncus semper orci sit amet pulvinar. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque vitae consequat dui. Suspendisse laoreet ut nulla eu dignissim. Curabitur fringilla, quam sit amet porta porttitor, orci dui pellentesque odio, et commodo sapien enim quis magna. Mauris posuere tempor tortor sed gravida. Duis mollis libero non commodo elementum. 86 | 87 | Vestibulum tempus, enim vel venenatis scelerisque, orci leo consequat libero, sed tempor ex lacus a magna. Phasellus ut lacinia diam, nec suscipit est. Praesent at efficitur ante. Suspendisse potenti. Donec vitae ornare erat. Sed ultricies quam sit amet vehicula ultrices. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc blandit lectus sed dapibus feugiat. Etiam consectetur dictum metus tincidunt eleifend. Cras dignissim orci ligula, in convallis nibh ornare nec. Maecenas iaculis ullamcorper auctor. Maecenas varius tortor libero, in volutpat velit luctus et. Morbi vel augue vitae augue egestas luctus. 88 | 89 | Duis sit amet elementum augue. Sed elementum posuere velit sed feugiat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Maecenas elit arcu, venenatis quis massa id, mollis venenatis purus. Curabitur ac metus tellus. Proin vulputate posuere est, at semper quam bibendum ut. Vestibulum vulputate sit amet sapien at blandit. 90 | 91 | Sed vel justo molestie, faucibus lacus nec, pellentesque enim. Vivamus a elit in mi mollis congue id non risus. Pellentesque quis faucibus neque. Curabitur ac nisi posuere leo dignissim condimentum ut eget ipsum. Mauris nunc mauris, mattis vitae quam vel, sollicitudin tincidunt est. In facilisis tortor tellus, non venenatis metus laoreet nec. Nullam tempus feugiat mauris sit amet hendrerit. Donec a mauris augue. Maecenas nec risus maximus, tempor sem id, sollicitudin turpis. Pellentesque elementum lorem facilisis eleifend consequat. 92 | 93 | Sed tincidunt volutpat eros in aliquam. Aenean lobortis velit magna, nec efficitur risus pulvinar ac. Mauris auctor efficitur finibus. Sed vel luctus nunc. Fusce vel tincidunt massa. Curabitur scelerisque enim tortor, at facilisis ipsum condimentum mollis. Nunc tempus orci a felis vehicula elementum. Etiam sed volutpat ligula. Vestibulum varius blandit varius. Aliquam id iaculis augue, nec dignissim lorem. Aenean placerat eros felis, in pretium tellus placerat id. Phasellus blandit ac neque id semper. 94 | 95 | Sed sollicitudin ligula a euismod tincidunt. Donec nisi dolor, aliquam non porta ut, ultricies vel nunc. Phasellus auctor, felis eget tempor vulputate, sem libero semper est, at gravida enim augue eu nisi. Suspendisse vitae convallis dolor. Donec convallis commodo augue, at ultricies dui efficitur id. Cras vitae facilisis sapien. Etiam sagittis risus vitae libero rutrum, non dignissim sapien elementum. Nullam at felis rutrum lorem dignissim ultrices. 96 | 97 | Vivamus tristique risus eu tellus vehicula, sit amet lobortis nulla tempor. Curabitur nibh nibh, consequat sit amet porta sagittis, commodo non nibh. Mauris ex nibh, posuere et erat nec, blandit molestie metus. Duis lacinia metus pulvinar laoreet aliquam. Vestibulum sagittis, ante et tempus aliquet, nisl justo lacinia neque, id aliquam tellus odio nec purus. Donec in tellus vitae est tincidunt maximus. Nulla elementum lectus in lectus interdum interdum. Pellentesque mattis imperdiet placerat. Suspendisse volutpat nisl tellus, in rhoncus quam semper ac. Vestibulum eget ipsum consequat, semper mi nec, placerat metus. Fusce aliquet congue nulla a tristique. Morbi ipsum dolor, imperdiet porta metus vitae, ullamcorper tincidunt nisl. Etiam cursus mauris elit, a blandit ex mattis a. Nullam placerat facilisis convallis. 98 | 99 | In et odio dignissim, blandit augue id, viverra felis. Maecenas suscipit eu metus eu viverra. Sed semper, tellus eget sagittis pellentesque, sapien ante scelerisque est, vehicula fermentum ligula mauris a eros. Etiam enim nisl, tincidunt non lacus ac, elementum sodales augue. Integer nulla felis, pellentesque at dolor id, pulvinar placerat risus. Ut sed semper nulla. In interdum quis eros vitae porta. Nulla sollicitudin justo varius lacinia mattis. Mauris id magna aliquet ipsum accumsan lobortis et ac ligula. 100 | 101 | Fusce arcu diam, tristique quis metus ac, laoreet malesuada purus. Aliquam vitae maximus velit. Nam eget posuere est, quis imperdiet massa. Aenean a tempor nisi. Mauris convallis ante sed purus efficitur, vitae porta purus pellentesque. Vivamus a velit vel turpis sagittis elementum nec ut augue. Fusce convallis sapien eu nisl aliquet, pulvinar posuere ex faucibus. Vestibulum tristique tellus at vulputate euismod. Ut vel nulla aliquet, tempus risus placerat, dapibus quam. 102 | 103 | Nunc tempor sed dolor non ultricies. Maecenas nulla odio, scelerisque sit amet dui vitae, facilisis mollis quam. Curabitur ultricies, enim ac consequat malesuada, diam mauris accumsan erat, sit amet finibus dui sapien vitae erat. Phasellus tristique molestie auctor. Ut a augue ac lacus dapibus blandit. Phasellus cursus consequat tellus in lobortis. Phasellus rutrum euismod purus, quis rhoncus enim suscipit nec. Duis pellentesque, quam sit amet accumsan sagittis, ante eros finibus mi, et semper neque mi at erat. Fusce blandit diam ligula, a auctor neque egestas non. 104 | 105 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc gravida velit nibh, sed suscipit lacus euismod sit amet. Nulla sodales libero blandit ullamcorper eleifend. Phasellus sodales eros vitae odio suscipit consequat. Cras ante risus, tristique ac sem a, cursus pharetra mauris. Aenean ac lacinia eros. Ut porta risus at pellentesque vehicula. Nulla ultrices lacinia lectus in suscipit. Suspendisse accumsan iaculis sapien non fringilla. Praesent eget ipsum eu sapien luctus vehicula. Etiam nec elit facilisis, aliquet mauris et, scelerisque neque. Cras tristique ac sapien et elementum. Curabitur sed pretium ante, nec ornare urna. Mauris ullamcorper purus lectus, et sodales dui viverra feugiat. Duis faucibus sem vel lorem aliquam viverra. 106 | 107 | Ut sit amet libero ante. Sed metus dui, convallis at massa id, luctus accumsan lacus. Phasellus at neque non tortor mattis iaculis vitae nec velit. Nullam ullamcorper ac velit eu consequat. Donec semper velit est, vitae vestibulum metus porta ac. Integer condimentum augue ut aliquam convallis. Nullam vestibulum consectetur velit in hendrerit. Sed eleifend risus quis nulla fermentum, quis euismod sapien vehicula. Fusce eu elementum odio. Sed sed metus lorem. Nunc erat lacus, cursus vitae rhoncus non, feugiat ac velit. Suspendisse orci leo, venenatis quis congue quis, lobortis vitae turpis. Aliquam erat volutpat. Nullam congue fringilla tortor, vestibulum feugiat odio condimentum et. Maecenas pellentesque arcu cursus sem imperdiet, eget eleifend magna consequat. 108 | 109 | Nullam at odio in mi lacinia fringilla sollicitudin sed est. Aliquam semper fringilla ornare. Maecenas eget urna eu tellus facilisis dapibus vitae a metus. Pellentesque congue, tortor vel ullamcorper imperdiet, odio urna porttitor nibh, ac elementum nisi risus tincidunt purus. Suspendisse eget erat molestie, dictum neque aliquet, dapibus enim. Nunc ac vestibulum sapien, at scelerisque nunc. Praesent bibendum condimentum turpis, vel semper neque viverra sed. Aliquam at finibus felis. Sed scelerisque sapien purus, id viverra velit mollis sed. Proin nec dolor eget augue mattis porta. Donec velit nulla, feugiat at pellentesque eu, venenatis vitae diam. Donec pulvinar, urna ullamcorper ornare placerat, odio massa consequat ante, bibendum aliquam odio ex sed nibh. Nunc malesuada metus ac lacinia tincidunt. Vestibulum non elit eu nunc ultricies volutpat a imperdiet purus. 110 | 111 | Maecenas fermentum lacus ut neque laoreet, ut scelerisque enim vulputate. Duis condimentum tortor nec elementum commodo. Morbi mi dolor, tempus quis enim vel, aliquam tincidunt mi. Suspendisse consequat justo turpis, vitae placerat tortor tincidunt sit amet. Donec fringilla ante ac mauris ullamcorper fermentum. Praesent eget viverra massa, sit amet vehicula mauris. Praesent non ipsum fermentum, imperdiet justo ac, scelerisque diam. Vivamus quam metus, vestibulum tempor nisl rhoncus, bibendum fringilla ex. Phasellus ut nisi ultrices, suscipit eros eu, dictum eros. Sed metus elit, efficitur ac efficitur tempus, efficitur id justo. Proin sodales nulla urna, eget maximus dolor vehicula id. Quisque laoreet, ipsum sit amet porta hendrerit, nunc orci egestas quam, sit amet eleifend nulla orci at diam. Quisque nec mollis nibh, ut sagittis orci. Pellentesque ac bibendum neque. Proin commodo eu metus ac tristique. 112 | 113 | Nam eget lorem ac elit bibendum condimentum vel ut sem. Nunc in sagittis elit. Aenean nisi ex, elementum eu tincidunt sed, gravida ac massa. Mauris sed erat dictum, lacinia ipsum vel, rhoncus leo. Proin et dapibus sapien, porttitor pretium tellus. Phasellus dapibus velit elit. Ut consequat id quam et posuere. 114 | 115 | Duis diam arcu, consectetur a ultrices vel, dictum sit amet libero. Morbi nec scelerisque quam. Nullam ut tortor ac velit accumsan posuere. Duis porta mauris et elementum sagittis. Etiam quis leo in libero scelerisque porttitor mattis blandit enim. Nulla commodo nunc vel nisl fermentum ultrices. Etiam et erat id enim gravida finibus. Maecenas eget quam et purus congue maximus bibendum sit amet tortor. 116 | 117 | Ut sed scelerisque lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec gravida viverra metus eu gravida. Nulla at justo diam. Quisque feugiat magna libero, et tempus metus feugiat a. Duis id ullamcorper ante. Sed vehicula pulvinar condimentum vel. -------------------------------------------------------------------------------- /examples/An image - if You like to include it in the document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorantica/plsql-word/907749e23225470dabe0d4a0685cd4474a307a46/examples/An image - if You like to include it in the document.png -------------------------------------------------------------------------------- /examples/p_create_word.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorantica/plsql-word/907749e23225470dabe0d4a0685cd4474a307a46/examples/p_create_word.sql -------------------------------------------------------------------------------- /package/ZT_WORD.pkb: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE PACKAGE BODY zt_word AS 2 | 3 | --global variables 4 | grDoc t_documents := t_documents(); 5 | gcClob clob; 6 | c_local_file_header constant raw(4) := hextoraw( '504B0304' ); 7 | c_end_of_central_directory constant raw(4) := hextoraw( '504B0506' ); 8 | 9 | grDefaultPage r_page := f_get_page( 10 | p_width => 11906, 11 | p_height => 16838, 12 | p_margin_top => 1417, 13 | p_margin_bottom => 1417, 14 | p_margin_left => 1417, 15 | p_margin_right => 1417, 16 | p_header_height => 708, 17 | p_footer_height => 708, 18 | p_orientation => 'portrait'); 19 | 20 | 21 | 22 | FUNCTION f_unit_convert( 23 | p_doc_id number default null, 24 | p_usage varchar2 default 'page', --values: page, image, image_rotate 25 | p_value number 26 | ) RETURN number IS 27 | 28 | lnIndex number; 29 | 30 | BEGIN 31 | if p_doc_id is null then 32 | RETURN p_value; 33 | end if; 34 | 35 | CASE 36 | WHEN p_usage = 'page' and grDoc(p_doc_id).unit = 'cm' THEN lnIndex := 567; 37 | WHEN p_usage = 'page' and grDoc(p_doc_id).unit = 'mm' THEN lnIndex := 56.7; 38 | WHEN p_usage = 'image' and grDoc(p_doc_id).unit = 'cm' THEN lnIndex := 360000; 39 | WHEN p_usage = 'image' and grDoc(p_doc_id).unit = 'mm' THEN lnIndex := 36000; 40 | WHEN p_usage = 'image_rotate' THEN lnIndex := 60000; 41 | ELSE lnIndex := 1; 42 | END CASE; 43 | 44 | RETURN round(p_value * lnIndex); 45 | END; 46 | 47 | 48 | FUNCTION f_explode(p_text in varchar2, 49 | p_delimiter in varchar2) RETURN t_table_vc2 IS 50 | 51 | lrList t_table_vc2 := t_table_vc2(); 52 | lnCounter pls_integer := 0; 53 | lcText varchar2(32000) := p_text; 54 | 55 | BEGIN 56 | LOOP 57 | lnCounter := instr(lcText, p_delimiter); 58 | 59 | if lnCounter > 0 then 60 | lrList.extend(1); 61 | lrList(lrList.count) := substr(lcText, 1, lnCounter - 1); 62 | lcText := substr(lcText, lnCounter + length(p_delimiter)); 63 | else 64 | lrList.extend(1); 65 | lrList(lrList.count) := lcText; 66 | return lrList; 67 | end if; 68 | 69 | END LOOP; 70 | 71 | END f_explode; 72 | 73 | 74 | FUNCTION c2b( 75 | p_clob clob, 76 | p_encoding IN NUMBER default 0) RETURN blob IS 77 | 78 | v_blob Blob; 79 | v_in Pls_Integer := 1; 80 | v_out Pls_Integer := 1; 81 | v_lang Pls_Integer := 0; 82 | v_warning Pls_Integer := 0; 83 | v_id number(10); 84 | 85 | BEGIN 86 | if p_clob is null then 87 | return null; 88 | end if; 89 | 90 | v_in:=1; 91 | v_out:=1; 92 | dbms_lob.createtemporary(v_blob,TRUE); 93 | DBMS_LOB.convertToBlob(v_blob, 94 | p_clob, 95 | DBMS_lob.getlength(p_clob), 96 | v_in, 97 | v_out, 98 | p_encoding, 99 | v_lang, 100 | v_warning); 101 | 102 | RETURN v_blob; 103 | 104 | END c2b; 105 | 106 | 107 | FUNCTION f_new_container( 108 | p_doc_id number, 109 | p_type varchar2 default 'DOCUMENT') RETURN pls_integer IS 110 | 111 | lnID pls_integer; 112 | 113 | BEGIN 114 | grDoc(p_doc_id).containers.extend; 115 | 116 | lnID := grDoc(p_doc_id).containers.count; 117 | 118 | grDoc(p_doc_id).containers(lnID).container_type := p_type; 119 | grDoc(p_doc_id).containers(lnID).elements := t_elements(); 120 | 121 | if p_type in ('HEADER', 'FOOTER') then 122 | grDoc(p_doc_id).containers(lnID).rel_id := grDoc(p_doc_id).rels_id; 123 | grDoc(p_doc_id).rels_id := grDoc(p_doc_id).rels_id + 1; 124 | end if; 125 | 126 | RETURN lnID; 127 | END; 128 | 129 | 130 | FUNCTION f_new_document( 131 | p_author varchar2 default null, 132 | p_default_page r_page default null, 133 | p_unit varchar2 default 'cm', 134 | p_lang varchar2 default 'en-US') RETURN pls_integer IS 135 | 136 | lnID pls_integer; 137 | lnID2 pls_integer; 138 | 139 | BEGIN 140 | grDoc.extend; 141 | lnID := grDoc.count; 142 | 143 | --document properties 144 | grDoc(lnID).author := p_author; 145 | grDoc(lnID).create_date := sysdate; 146 | grDoc(lnID).rels_id := 10; 147 | 148 | if p_default_page.width is not null then 149 | grDoc(lnID).default_page := p_default_page; 150 | else 151 | grDoc(lnID).default_page := grDefaultPage; 152 | end if; 153 | 154 | grDoc(lnID).unit := p_unit; 155 | grDoc(lnID).lang := p_lang; 156 | 157 | --containers init - first one is document 158 | grDoc(lnID).containers := t_containers(); 159 | lnID2 := f_new_container(lnID); 160 | 161 | --lists init 162 | grDoc(lnID).lists := t_list(); 163 | 164 | --images init 165 | grDoc(lnID).images := t_images(); 166 | 167 | RETURN lnID; 168 | END; 169 | 170 | 171 | FUNCTION f_new_paragraph( 172 | p_doc_id number, 173 | p_container_id pls_integer default null, 174 | p_alignment_h varchar2 default 'LEFT', 175 | p_space_before number default 0, 176 | p_space_after number default 0, 177 | p_style varchar2 default null, 178 | p_list_id pls_integer default null, 179 | p_text varchar2 default null, 180 | p_font r_font default null, 181 | p_replace_newline boolean default false, 182 | p_newline_character varchar2 default chr(10), 183 | p_text_clob clob default null 184 | ) RETURN pls_integer IS 185 | 186 | lnID pls_integer; 187 | lnContainerID pls_integer := nvl(p_container_id, 1); 188 | 189 | BEGIN 190 | grDoc(p_doc_id).containers(lnContainerID).elements.extend; 191 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements.count; 192 | 193 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).element_type := 'PARAGRAPH'; 194 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).paragraph.alignment_h := p_alignment_h; 195 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).paragraph.space_before := p_space_before; 196 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).paragraph.space_after := p_space_after; 197 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).paragraph.style := p_style; 198 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).paragraph.list_id := p_list_id; 199 | 200 | if p_text is not null then 201 | p_add_text( 202 | p_doc_id => p_doc_id, 203 | p_container_id => lnContainerID, 204 | p_paragraph_id => lnID, 205 | p_text => p_text, 206 | p_font => p_font, 207 | p_replace_newline => p_replace_newline, 208 | p_newline_character => p_newline_character 209 | ); 210 | elsif p_text_clob is not null then 211 | 212 | DECLARE 213 | l_counter pls_integer := 0; 214 | l_text varchar2(30000); 215 | BEGIN 216 | 217 | LOOP 218 | 219 | l_text := substr(p_text_clob, 1 + 30000 * l_counter, 30000); 220 | EXIT WHEN l_text is null OR l_counter > 10; 221 | 222 | p_add_text( 223 | p_doc_id => p_doc_id, 224 | p_container_id => lnContainerID, 225 | p_paragraph_id => lnID, 226 | p_text => l_text, 227 | p_font => p_font, 228 | p_replace_newline => p_replace_newline, 229 | p_newline_character => p_newline_character 230 | ); 231 | 232 | l_counter := l_counter + 1; 233 | 234 | END LOOP; 235 | 236 | END; 237 | 238 | end if; 239 | 240 | RETURN lnID; 241 | END; 242 | 243 | 244 | FUNCTION f_image_data( 245 | p_image_id pls_integer, 246 | p_width number default 0, 247 | p_height number default 0, 248 | p_rotate_angle number default 0, 249 | p_extent_area_left number default 0, 250 | p_extent_area_top number default 0, 251 | p_extent_area_right number default 0, 252 | p_extent_area_bottom number default 0, 253 | p_inline_yn varchar2 default 'Y', 254 | p_relative_from_h varchar2 default 'page', --page, margin, column 255 | p_position_type_h varchar2 default 'align', --align, posOffset 256 | p_position_align_h varchar2 default 'center', --left, right, center 257 | p_position_h number default 0, --offset from object 258 | p_relative_from_v varchar2 default 'page', 259 | p_position_type_v varchar2 default 'align', 260 | p_position_align_v varchar2 default 'center', --top, bottom, center 261 | p_position_v number default 0 262 | ) RETURN r_image_data IS 263 | 264 | lrImageParams r_image_data; 265 | 266 | BEGIN 267 | lrImageParams.image_id := p_image_id; 268 | lrImageParams.width := p_width; 269 | lrImageParams.height := p_height; 270 | lrImageParams.rotate_angle := p_rotate_angle; 271 | lrImageParams.extent_area_left := p_extent_area_left; 272 | lrImageParams.extent_area_top := p_extent_area_top; 273 | lrImageParams.extent_area_right := p_extent_area_right; 274 | lrImageParams.extent_area_bottom := p_extent_area_bottom; 275 | lrImageParams.inline_yn := p_inline_yn; 276 | lrImageParams.relative_from_h := p_relative_from_h; 277 | lrImageParams.position_type_h := p_position_type_h; 278 | lrImageParams.position_align_h := p_position_align_h; 279 | lrImageParams.position_h := p_position_h; 280 | lrImageParams.relative_from_v := p_relative_from_v; 281 | lrImageParams.position_type_v := p_position_type_v; 282 | lrImageParams.position_align_v := p_position_align_v; 283 | lrImageParams.position_v := p_position_v; 284 | 285 | RETURN lrImageParams; 286 | END f_image_data; 287 | 288 | FUNCTION f_add_image_to_document( 289 | p_doc_id number, 290 | p_filename varchar2, 291 | p_image blob 292 | ) RETURN pls_integer IS 293 | 294 | lnID pls_integer; 295 | 296 | BEGIN 297 | grDoc(p_doc_id).images.extend; 298 | lnID := grDoc(p_doc_id).images.count; 299 | 300 | grDoc(p_doc_id).images(lnID).image_name := p_filename; 301 | grDoc(p_doc_id).images(lnID).image_file := p_image; 302 | 303 | grDoc(p_doc_id).images(lnID).rel_id := grDoc(p_doc_id).rels_id; 304 | grDoc(p_doc_id).rels_id := grDoc(p_doc_id).rels_id + 1; 305 | 306 | RETURN lnID; 307 | END f_add_image_to_document; 308 | 309 | 310 | 311 | FUNCTION f_new_image_instance( 312 | p_doc_id number, 313 | p_container_id pls_integer default null, 314 | p_image_data r_image_data 315 | ) RETURN pls_integer IS 316 | 317 | lnID pls_integer; 318 | lnContainerID pls_integer := nvl(p_container_id, 1); 319 | 320 | BEGIN 321 | grDoc(p_doc_id).containers(lnContainerID).elements.extend; 322 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements.count; 323 | 324 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).element_type := 'IMAGE'; 325 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).image_data := p_image_data; 326 | 327 | RETURN lnID; 328 | END f_new_image_instance; 329 | 330 | 331 | 332 | FUNCTION f_border( 333 | p_border_type varchar2 default null, 334 | p_width number default null, 335 | p_color varchar2 default null 336 | ) RETURN r_border IS 337 | 338 | lrBorder r_border; 339 | 340 | BEGIN 341 | lrBorder.border_type := p_border_type; 342 | lrBorder.width := p_width; 343 | lrBorder.color := p_color; 344 | 345 | RETURN lrBorder; 346 | END; 347 | 348 | 349 | PROCEDURE p_table_cell( 350 | p_doc_id number, 351 | p_table_id pls_integer, 352 | p_row pls_integer, 353 | p_column pls_integer, 354 | p_alignment_h varchar2 default 'LEFT', 355 | p_alignment_v varchar2 default 'TOP', 356 | p_border_top r_border default null, 357 | p_border_bottom r_border default null, 358 | p_border_left r_border default null, 359 | p_border_right r_border default null, 360 | p_background_color varchar2 default null, 361 | p_text varchar2 default null, 362 | p_font r_font default null, 363 | p_image_data r_image_data default null, 364 | p_container_id pls_integer default null 365 | ) IS 366 | 367 | lnID pls_integer; 368 | lnContainerID pls_integer := nvl(p_container_id, 1); 369 | 370 | BEGIN 371 | --texts init 372 | if grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts is null then 373 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts := t_text(); 374 | end if; 375 | 376 | --alignment 377 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.alignment_h := p_alignment_h; 378 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).alignment_v := p_alignment_v; 379 | 380 | --background color 381 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).background_color := p_background_color; 382 | 383 | --borders 384 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).border_top := p_border_top; 385 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).border_bottom := p_border_bottom; 386 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).border_left := p_border_left; 387 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).border_right := p_border_right; 388 | 389 | --text 390 | if p_text is not null or p_image_data.image_id is not null then 391 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts.extend; 392 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts.count; 393 | 394 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts(lnID).text := p_text; 395 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts(lnID).font := p_font; 396 | 397 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_row || ',' || p_column).paragraph.texts(lnID).image_data := p_image_data; 398 | end if; 399 | END p_table_cell; 400 | 401 | 402 | PROCEDURE p_table_column_width( 403 | p_doc_id pls_integer, 404 | p_table_id pls_integer, 405 | p_width varchar2, 406 | p_container_id pls_integer default null) IS 407 | 408 | lcSirina varchar2(10000) := replace(p_width, ' ', null); 409 | lrVrednosti t_table_vc2; 410 | lnContainerID pls_integer := nvl(p_container_id, 1); 411 | 412 | BEGIN 413 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.column_width := t_table_number(); 414 | 415 | lrVrednosti := f_explode(lcSirina, ','); 416 | 417 | FOR t IN 1 .. lrVrednosti.count LOOP 418 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.column_width.extend; 419 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.column_width(t) := to_number(lrVrednosti(t)); 420 | END LOOP; 421 | 422 | END; 423 | 424 | 425 | PROCEDURE p_table_merge_cells( 426 | p_doc_id number, 427 | p_table_id pls_integer, 428 | p_from_row pls_integer, 429 | p_from_column pls_integer, 430 | p_to_row pls_integer, 431 | p_to_column pls_integer, 432 | p_container_id pls_integer default null) IS 433 | 434 | lnContainerID pls_integer := nvl(p_container_id, 1); 435 | 436 | BEGIN 437 | --if vertical merge exists -> mark cells 438 | if p_from_row <> p_to_row then 439 | --mark first row 440 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(p_from_row || ',' || p_from_column).merge_v := ''; 441 | 442 | --mark other rows till last row 443 | FOR t IN (p_from_row + 1) .. p_to_row LOOP 444 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(t || ',' || p_from_column).merge_v := ''; 445 | END LOOP; 446 | end if; 447 | 448 | --if horizontal merge exists -> mark cells 449 | if p_from_column <> p_to_column then 450 | --for each row merge cells -> mark gridSpan number; other columns mark with -1 (ignore in XML document) 451 | FOR t IN p_from_row .. p_to_row LOOP 452 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(t || ',' || p_from_column).merge_h := p_to_column - p_from_column + 1; 453 | FOR p IN (p_from_column + 1) .. p_to_column LOOP 454 | grDoc(p_doc_id).containers(lnContainerID).elements(p_table_id).table_data.cells(t || ',' || p).merge_h := -1; 455 | END LOOP; 456 | END LOOP; 457 | end if; 458 | END; 459 | 460 | FUNCTION f_new_table( 461 | p_doc_id number, 462 | p_rows pls_integer, 463 | p_columns pls_integer, 464 | p_table_width pls_integer default null, 465 | p_columns_width varchar2 default null, 466 | p_border_top r_border default null, 467 | p_border_bottom r_border default null, 468 | p_border_left r_border default null, 469 | p_border_right r_border default null, 470 | p_border_inside_h r_border default null, 471 | p_border_inside_v r_border default null, 472 | p_container_id pls_integer default null 473 | ) RETURN pls_integer IS 474 | 475 | lnID pls_integer; 476 | lnContainerID pls_integer := nvl(p_container_id, 1); 477 | 478 | BEGIN 479 | grDoc(p_doc_id).containers(lnContainerID).elements.extend; 480 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements.count; 481 | 482 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).element_type := 'TABLE'; 483 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.rows_num := p_rows; 484 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.columns_num := p_columns; 485 | 486 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.width := p_table_width; 487 | 488 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_top := p_border_top; 489 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_bottom := p_border_bottom; 490 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_left := p_border_left; 491 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_right := p_border_right; 492 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_inside_h := p_border_inside_h; 493 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.border_inside_v := p_border_inside_v; 494 | 495 | p_table_column_width( 496 | p_doc_id => p_doc_id, 497 | p_container_id => lnContainerID, 498 | p_table_id => lnID, 499 | p_width => p_columns_width 500 | ); 501 | 502 | --create cells 503 | FOR v IN 1 .. p_rows LOOP 504 | FOR s IN 1 .. p_columns LOOP 505 | grDoc(p_doc_id).containers(lnContainerID).elements(lnID).table_data.cells(v || ',' || s) := null; 506 | END LOOP; 507 | END LOOP; 508 | 509 | RETURN lnID; 510 | END; 511 | 512 | 513 | 514 | FUNCTION f_new_numbering( 515 | p_doc_id number, 516 | p_start_value varchar2 default '1') RETURN pls_integer IS 517 | 518 | lnID pls_integer; 519 | 520 | BEGIN 521 | grDoc(p_doc_id).lists.extend; 522 | lnID := grDoc(p_doc_id).lists.count; 523 | 524 | grDoc(p_doc_id).lists(lnID).list_type := 'decimal'; 525 | grDoc(p_doc_id).lists(lnID).num_start_value := p_start_value; 526 | 527 | RETURN lnID; 528 | END; 529 | 530 | 531 | FUNCTION f_new_bullet( 532 | p_doc_id number, 533 | p_char varchar2 default 'o', 534 | p_font varchar2 default 'Courier New') RETURN pls_integer IS 535 | 536 | lnID pls_integer; 537 | 538 | BEGIN 539 | grDoc(p_doc_id).lists.extend; 540 | lnID := grDoc(p_doc_id).lists.count; 541 | 542 | grDoc(p_doc_id).lists(lnID).list_type := 'bullet'; 543 | grDoc(p_doc_id).lists(lnID).bullet_char := p_char; 544 | grDoc(p_doc_id).lists(lnID).bullet_font := p_font; 545 | 546 | RETURN lnID; 547 | END; 548 | 549 | 550 | FUNCTION f_new_page_break(p_doc_id number) RETURN pls_integer IS 551 | 552 | lnID pls_integer; 553 | 554 | BEGIN 555 | grDoc(p_doc_id).containers(1).elements.extend; 556 | lnID := grDoc(p_doc_id).containers(1).elements.count; 557 | 558 | grDoc(p_doc_id).containers(1).elements(lnID).element_type := 'BREAK'; 559 | 560 | grDoc(p_doc_id).containers(1).elements(lnID).break_data.break_type := 'PAGE'; 561 | 562 | RETURN lnID; 563 | END; 564 | 565 | 566 | FUNCTION f_new_section_break( 567 | p_doc_id number, 568 | p_section_type varchar2, 569 | p_page_template varchar2 default null, 570 | p_page r_page default null) RETURN pls_integer IS 571 | 572 | lnID pls_integer; 573 | 574 | BEGIN 575 | grDoc(p_doc_id).containers(1).elements.extend; 576 | lnID := grDoc(p_doc_id).containers(1).elements.count; 577 | 578 | grDoc(p_doc_id).containers(1).elements(lnID).element_type := 'BREAK'; 579 | 580 | grDoc(p_doc_id).containers(1).elements(lnID).break_data.break_type := 'SECTION'; 581 | grDoc(p_doc_id).containers(1).elements(lnID).break_data.section_type := p_section_type; 582 | 583 | if nvl(p_page_template, 'x') = 'default' then 584 | grDoc(p_doc_id).containers(1).elements(lnID).break_data.page := grDoc(p_doc_id).default_page; 585 | else 586 | grDoc(p_doc_id).containers(1).elements(lnID).break_data.page := p_page; 587 | end if; 588 | 589 | RETURN lnID; 590 | END; 591 | 592 | 593 | PROCEDURE p_set_default_page( 594 | p_doc_id number, 595 | p_page r_page) IS 596 | BEGIN 597 | grDoc(p_doc_id).default_page := p_page; 598 | END; 599 | 600 | FUNCTION f_get_default_page( 601 | p_doc_id number) RETURN r_page IS 602 | BEGIN 603 | RETURN grDoc(p_doc_id).default_page; 604 | END; 605 | 606 | FUNCTION f_get_page( 607 | p_doc_id number default null, 608 | p_width number, 609 | p_height number, 610 | p_margin_top number, 611 | p_margin_bottom number, 612 | p_margin_left number, 613 | p_margin_right number, 614 | p_header_height number, 615 | p_footer_height number, 616 | p_header_ref pls_integer default null, 617 | p_footer_ref pls_integer default null, 618 | p_orientation varchar2) RETURN r_page IS 619 | 620 | lrPage zt_word.r_page; 621 | 622 | BEGIN 623 | lrPage.width := f_unit_convert(p_doc_id, 'page', p_width); 624 | lrPage.height := f_unit_convert(p_doc_id, 'page', p_height); 625 | 626 | lrPage.margin_top := f_unit_convert(p_doc_id, 'page', p_margin_top); 627 | lrPage.margin_bottom := f_unit_convert(p_doc_id, 'page', p_margin_bottom); 628 | lrPage.margin_left := f_unit_convert(p_doc_id, 'page', p_margin_left); 629 | lrPage.margin_right := f_unit_convert(p_doc_id, 'page', p_margin_right); 630 | 631 | lrPage.header_h := f_unit_convert(p_doc_id, 'page', p_header_height); 632 | lrPage.footer_h := f_unit_convert(p_doc_id, 'page', p_footer_height); 633 | 634 | lrPage.header_ref := f_unit_convert(p_doc_id, 'page', p_header_ref); 635 | lrPage.footer_ref := f_unit_convert(p_doc_id, 'page', p_footer_ref); 636 | 637 | lrPage.orientation := p_orientation; 638 | 639 | RETURN lrPage; 640 | END; 641 | 642 | FUNCTION f_font( 643 | p_from_paragraph boolean default false, 644 | p_font_name varchar2 default 'Calibri', 645 | p_font_size number default 11, 646 | p_bold boolean default false, 647 | p_italic boolean default false, 648 | p_underline boolean default false, 649 | p_color varchar2 default '000000') RETURN r_font IS 650 | 651 | lrFont r_font; 652 | 653 | BEGIN 654 | lrFont.from_paragraph := p_from_paragraph; 655 | lrFont.font_name := p_font_name; 656 | lrFont.font_size := p_font_size; 657 | lrFont.bold := p_bold; 658 | lrFont.italic := p_italic; 659 | lrFont.underline := p_underline; 660 | lrFont.color := p_color; 661 | 662 | RETURN lrFont; 663 | END; 664 | 665 | 666 | PROCEDURE p_add_text( 667 | p_doc_id number, 668 | p_container_id pls_integer default null, 669 | p_paragraph_id number, 670 | p_text varchar2 default null, 671 | p_font r_font default null, 672 | p_image_data r_image_data default null, 673 | p_replace_newline boolean default false, 674 | p_newline_character varchar2 default chr(10), 675 | p_text_clob clob default null 676 | ) IS 677 | 678 | lnID number; 679 | lnContainerID pls_integer := nvl(p_container_id, 1); 680 | 681 | BEGIN 682 | if p_text is null and p_text_clob is not null then 683 | 684 | DECLARE 685 | l_counter pls_integer := 0; 686 | l_text varchar2(30000); 687 | BEGIN 688 | 689 | LOOP 690 | 691 | l_text := substr(p_text_clob, 1 + 30000 * l_counter, 30000); 692 | EXIT WHEN l_text is null OR l_counter > 10; 693 | 694 | p_add_text( 695 | p_doc_id => p_doc_id, 696 | p_container_id => lnContainerID, 697 | p_paragraph_id => lnID, 698 | p_text => l_text, 699 | p_font => p_font, 700 | p_replace_newline => p_replace_newline, 701 | p_newline_character => p_newline_character 702 | ); 703 | 704 | l_counter := l_counter + 1; 705 | 706 | END LOOP; 707 | 708 | END; 709 | 710 | end if; 711 | 712 | if grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts is null then 713 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts := t_text(); 714 | end if; 715 | 716 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts.extend; 717 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts.count; 718 | 719 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).text := p_text; 720 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).font := p_font; 721 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).replace_newline := p_replace_newline; 722 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).newline_character := p_newline_character; 723 | 724 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).image_data := p_image_data; 725 | END p_add_text; 726 | 727 | PROCEDURE p_add_line_break ( 728 | p_doc_id number, 729 | p_container_id pls_integer default null, 730 | p_paragraph_id number 731 | ) IS 732 | 733 | lnID number; 734 | lnContainerID pls_integer := nvl(p_container_id, 1); 735 | 736 | BEGIN 737 | if grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts is null then 738 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts := t_text(); 739 | end if; 740 | 741 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts.extend; 742 | lnID := grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts.count; 743 | 744 | grDoc(p_doc_id).containers(lnContainerID).elements(p_paragraph_id).paragraph.texts(lnID).line_break := true; 745 | 746 | END p_add_line_break; 747 | 748 | 749 | function little_endian( p_big number, p_bytes pls_integer := 4 ) 750 | return raw 751 | is 752 | begin 753 | return utl_raw.substr( utl_raw.cast_from_binary_integer( p_big, utl_raw.little_endian ), 1, p_bytes ); 754 | end; 755 | 756 | function blob2num( p_blob blob, p_len integer, p_pos integer ) 757 | return number 758 | is 759 | begin 760 | return utl_raw.cast_to_binary_integer( dbms_lob.substr( p_blob, p_len, p_pos ), utl_raw.little_endian ); 761 | end; 762 | 763 | 764 | procedure add1file 765 | ( p_zipped_blob in out blob 766 | , p_name varchar2 767 | , p_content blob 768 | ) 769 | is 770 | t_now date; 771 | t_blob blob; 772 | t_len integer; 773 | t_clen integer; 774 | t_crc32 raw(4) := hextoraw( '00000000' ); 775 | t_compressed boolean := false; 776 | t_name raw(32767); 777 | begin 778 | t_now := sysdate; 779 | t_len := nvl( dbms_lob.getlength( p_content ), 0 ); 780 | if t_len > 0 781 | then 782 | t_blob := utl_compress.lz_compress( p_content ); 783 | t_clen := dbms_lob.getlength( t_blob ) - 18; 784 | t_compressed := t_clen < t_len; 785 | t_crc32 := dbms_lob.substr( t_blob, 4, t_clen + 11 ); 786 | end if; 787 | if not t_compressed 788 | then 789 | t_clen := t_len; 790 | t_blob := p_content; 791 | end if; 792 | if p_zipped_blob is null 793 | then 794 | dbms_lob.createtemporary( p_zipped_blob, true ); 795 | end if; 796 | t_name := utl_i18n.string_to_raw( p_name, 'AL32UTF8' ); 797 | dbms_lob.append( p_zipped_blob 798 | , utl_raw.concat( c_LOCAL_FILE_HEADER -- Local file header signature 799 | , hextoraw( '1400' ) -- version 2.0 800 | , case when t_name = utl_i18n.string_to_raw( p_name, 'US8PC437' ) 801 | then hextoraw( '0000' ) -- no General purpose bits 802 | else hextoraw( '0008' ) -- set Language encoding flag (EFS) 803 | end 804 | , case when t_compressed 805 | then hextoraw( '0800' ) -- deflate 806 | else hextoraw( '0000' ) -- stored 807 | end 808 | , little_endian( to_number( to_char( t_now, 'ss' ) ) / 2 809 | + to_number( to_char( t_now, 'mi' ) ) * 32 810 | + to_number( to_char( t_now, 'hh24' ) ) * 2048 811 | , 2 812 | ) -- File last modification time 813 | , little_endian( to_number( to_char( t_now, 'dd' ) ) 814 | + to_number( to_char( t_now, 'mm' ) ) * 32 815 | + ( to_number( to_char( t_now, 'yyyy' ) ) - 1980 ) * 512 816 | , 2 817 | ) -- File last modification date 818 | , t_crc32 -- CRC-32 819 | , little_endian( t_clen ) -- compressed size 820 | , little_endian( t_len ) -- uncompressed size 821 | , little_endian( utl_raw.length( t_name ), 2 ) -- File name length 822 | , hextoraw( '0000' ) -- Extra field length 823 | , t_name -- File name 824 | ) 825 | ); 826 | if t_compressed 827 | then 828 | dbms_lob.copy( p_zipped_blob, t_blob, t_clen, dbms_lob.getlength( p_zipped_blob ) + 1, 11 ); -- compressed content 829 | elsif t_clen > 0 830 | then 831 | dbms_lob.copy( p_zipped_blob, t_blob, t_clen, dbms_lob.getlength( p_zipped_blob ) + 1, 1 ); -- content 832 | end if; 833 | if dbms_lob.istemporary( t_blob ) = 1 834 | then 835 | dbms_lob.freetemporary( t_blob ); 836 | end if; 837 | end; 838 | -- 839 | procedure finish_zip( p_zipped_blob in out blob ) 840 | is 841 | t_cnt pls_integer := 0; 842 | t_offs integer; 843 | t_offs_dir_header integer; 844 | t_offs_end_header integer; 845 | t_comment raw(32767) := utl_raw.cast_to_raw( 'Implementation by Anton Scheffer' ); 846 | begin 847 | t_offs_dir_header := dbms_lob.getlength( p_zipped_blob ); 848 | t_offs := 1; 849 | while dbms_lob.substr( p_zipped_blob, utl_raw.length( c_LOCAL_FILE_HEADER ), t_offs ) = c_LOCAL_FILE_HEADER 850 | loop 851 | t_cnt := t_cnt + 1; 852 | dbms_lob.append( p_zipped_blob 853 | , utl_raw.concat( hextoraw( '504B0102' ) -- Central directory file header signature 854 | , hextoraw( '1400' ) -- version 2.0 855 | , dbms_lob.substr( p_zipped_blob, 26, t_offs + 4 ) 856 | , hextoraw( '0000' ) -- File comment length 857 | , hextoraw( '0000' ) -- Disk number where file starts 858 | , hextoraw( '0000' ) -- Internal file attributes => 859 | -- 0000 binary file 860 | -- 0100 (ascii)text file 861 | , case 862 | when dbms_lob.substr( p_zipped_blob 863 | , 1 864 | , t_offs + 30 + blob2num( p_zipped_blob, 2, t_offs + 26 ) - 1 865 | ) in ( hextoraw( '2F' ) -- / 866 | , hextoraw( '5C' ) -- \ 867 | ) 868 | then hextoraw( '10000000' ) -- a directory/folder 869 | else hextoraw( '2000B681' ) -- a file 870 | end -- External file attributes 871 | , little_endian( t_offs - 1 ) -- Relative offset of local file header 872 | , dbms_lob.substr( p_zipped_blob 873 | , blob2num( p_zipped_blob, 2, t_offs + 26 ) 874 | , t_offs + 30 875 | ) -- File name 876 | ) 877 | ); 878 | t_offs := t_offs + 30 + blob2num( p_zipped_blob, 4, t_offs + 18 ) -- compressed size 879 | + blob2num( p_zipped_blob, 2, t_offs + 26 ) -- File name length 880 | + blob2num( p_zipped_blob, 2, t_offs + 28 ); -- Extra field length 881 | end loop; 882 | t_offs_end_header := dbms_lob.getlength( p_zipped_blob ); 883 | dbms_lob.append( p_zipped_blob 884 | , utl_raw.concat( c_END_OF_CENTRAL_DIRECTORY -- End of central directory signature 885 | , hextoraw( '0000' ) -- Number of this disk 886 | , hextoraw( '0000' ) -- Disk where central directory starts 887 | , little_endian( t_cnt, 2 ) -- Number of central directory records on this disk 888 | , little_endian( t_cnt, 2 ) -- Total number of central directory records 889 | , little_endian( t_offs_end_header - t_offs_dir_header ) -- Size of central directory 890 | , little_endian( t_offs_dir_header ) -- Offset of start of central directory, relative to start of archive 891 | , little_endian( nvl( utl_raw.length( t_comment ), 0 ), 2 ) -- ZIP file comment length 892 | , t_comment 893 | ) 894 | ); 895 | end finish_zip; 896 | 897 | 898 | 899 | 900 | PROCEDURE p_add_document_to_zip( 901 | p_zip IN OUT blob, 902 | p_name varchar2, 903 | p_document clob 904 | ) IS 905 | 906 | lbBlob blob; 907 | 908 | BEGIN 909 | lbBlob := c2b(p_document); 910 | add1file(p_zip, p_name, lbBlob); 911 | END p_add_document_to_zip; 912 | 913 | 914 | PROCEDURE p_add_document_to_zip( 915 | p_zip IN OUT blob, 916 | p_name varchar2, 917 | p_document blob 918 | ) IS 919 | 920 | BEGIN 921 | add1file(p_zip, p_name, p_document); 922 | END p_add_document_to_zip; 923 | 924 | 925 | 926 | 927 | 928 | FUNCTION f_content_types(p_doc_id number) RETURN clob IS 929 | lcClob clob; 930 | 931 | BEGIN 932 | lcClob := ' 933 | 934 | 935 | 936 | 937 | 938 | ' || 939 | (CASE WHEN grDoc(p_doc_id).lists.count = 0 THEN null ELSE '' END) || 940 | ' 941 | 942 | 943 | 944 | 945 | 946 | 947 | '; 948 | 949 | FOR t IN grDoc(p_doc_id).containers.first .. grDoc(p_doc_id).containers.last LOOP 950 | if grDoc(p_doc_id).containers(t).container_type = 'HEADER' then 951 | lcClob := lcClob || chr(10) || ''; 952 | elsif grDoc(p_doc_id).containers(t).container_type = 'FOOTER' then 953 | lcClob := lcClob || chr(10) || ''; 954 | end if; 955 | END LOOP; 956 | 957 | lcClob := lcClob || chr(10) || ''; 958 | 959 | RETURN lcClob; 960 | END f_content_types; 961 | 962 | 963 | FUNCTION f_rels RETURN clob IS 964 | BEGIN 965 | RETURN ' 966 | 967 | 968 | 969 | 970 | '; 971 | END f_rels; 972 | 973 | 974 | FUNCTION f_app RETURN clob IS 975 | BEGIN 976 | RETURN ' 977 | 978 | 979 | 1 980 | 1 981 | 10 982 | 58 983 | Microsoft Office Word 984 | 0 985 | 1 986 | 1 987 | false 988 | 989 | false 990 | 67 991 | false 992 | false 993 | 15.0000 994 | '; 995 | END f_app; 996 | 997 | FUNCTION f_core(p_doc_id number) RETURN clob IS 998 | BEGIN 999 | RETURN ' 1000 | 1001 | 1002 | 1003 | ' || grDoc(p_doc_id).author || ' 1004 | 1005 | 1006 | ' || grDoc(p_doc_id).author || ' 1007 | 2 1008 | ' || to_char(grDoc(p_doc_id).create_date, 'yyyy-mm-dd') || 'T' || to_char(grDoc(p_doc_id).create_date, 'hh24:mi:ss') || 'Z 1009 | ' || to_char(grDoc(p_doc_id).create_date, 'yyyy-mm-dd') || 'T' || to_char(grDoc(p_doc_id).create_date, 'hh24:mi:ss') || 'Z 1010 | '; 1011 | END f_core; 1012 | 1013 | 1014 | 1015 | FUNCTION f_document_xml_rels( 1016 | p_doc_id pls_integer 1017 | ) RETURN clob IS 1018 | 1019 | lcRels clob; 1020 | 1021 | BEGIN 1022 | lcRels := ' 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | ' || 1029 | (CASE WHEN grDoc(p_doc_id).lists.count = 0 THEN null ELSE chr(10) || ' ' END); 1030 | 1031 | --references for headers and footers 1032 | FOR t IN grDoc(p_doc_id).containers.first .. grDoc(p_doc_id).containers.last LOOP 1033 | if grDoc(p_doc_id).containers(t).container_type = 'HEADER' then 1034 | lcRels := lcRels || chr(10) || 1035 | ' '; 1040 | elsif grDoc(p_doc_id).containers(t).container_type = 'FOOTER' then 1041 | lcRels := lcRels || chr(10) || 1042 | ' '; 1047 | end if; 1048 | END LOOP; 1049 | 1050 | --references for images 1051 | FOR t IN 1 .. grDoc(p_doc_id).images.count LOOP 1052 | lcRels := lcRels || chr(10) || 1053 | chr(9) || ''; 1058 | END LOOP; 1059 | 1060 | 1061 | lcRels := lcRels || chr(10) || ''; 1062 | 1063 | RETURN lcRels; 1064 | END f_document_xml_rels; 1065 | 1066 | 1067 | FUNCTION f_container_xml_rels( 1068 | p_doc_id pls_integer 1069 | ) RETURN clob IS 1070 | 1071 | lcRels clob; 1072 | 1073 | BEGIN 1074 | lcRels := ' 1075 | '; 1076 | 1077 | --references for images 1078 | FOR t IN 1 .. grDoc(p_doc_id).images.count LOOP 1079 | lcRels := lcRels || chr(10) || 1080 | chr(9) || ''; 1085 | END LOOP; 1086 | 1087 | lcRels := lcRels || chr(10) || ''; 1088 | 1089 | RETURN lcRels; 1090 | END f_container_xml_rels; 1091 | 1092 | 1093 | FUNCTION f_theme RETURN clob IS 1094 | BEGIN 1095 | RETURN ' 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | 1353 | '; 1354 | END f_theme; 1355 | 1356 | 1357 | 1358 | FUNCTION f_font_table RETURN clob IS 1359 | BEGIN 1360 | RETURN ' 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | '; 1384 | END f_font_table; 1385 | 1386 | /* 1387 | FUNCTION f_add_image (p_image_name varchar2, p_params r_image_params) RETURN CLOB IS 1388 | BEGIN 1389 | 1390 | RETURN ' 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | '||p_params.offset_h||' 1401 | 1402 | 1403 | '||p_params.offset_v||' 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 0 1445 | 1446 | 1447 | 0 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | '; 1454 | END f_add_image; 1455 | */ 1456 | 1457 | FUNCTION f_settings(p_doc_id number) RETURN clob IS 1458 | BEGIN 1459 | RETURN ' 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 1504 | '; 1505 | END f_settings; 1506 | 1507 | 1508 | FUNCTION f_styles(p_doc_id number) RETURN clob IS 1509 | lcClob clob; 1510 | BEGIN 1511 | lcClob := ' 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | 1525 | 1526 | 1527 | 1528 | 1529 | 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 | 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | 1612 | 1613 | 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1644 | 1645 | 1646 | 1647 | 1648 | 1649 | 1650 | 1651 | 1652 | 1653 | 1654 | 1655 | 1656 | 1657 | 1658 | 1659 | 1660 | 1661 | 1662 | 1663 | 1664 | 1665 | 1666 | 1667 | 1668 | 1669 | 1670 | 1671 | 1672 | 1673 | 1674 | 1675 | 1676 | 1677 | 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 1694 | 1695 | 1696 | 1697 | 1698 | 1699 | 1700 | 1701 | 1702 | 1703 | 1704 | 1705 | 1706 | 1707 | 1708 | 1709 | 1710 | 1711 | 1712 | 1713 | 1714 | 1715 | 1716 | 1717 | 1718 | 1719 | 1720 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 | 1736 | 1737 | 1738 | 1739 | 1740 | 1741 | 1742 | 1743 | 1744 | 1745 | 1746 | 1747 | 1748 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 1759 | 1760 | 1761 | 1762 | 1763 | 1764 | 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 | 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | 1792 | 1793 | 1794 | 1795 | 1796 | 1797 | 1798 | 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | 1809 | 1810 | 1811 | 1812 | 1813 | 1814 | 1815 | 1816 | 1817 | 1818 | 1819 | 1820 | 1821 | 1822 | 1823 | 1824 | 1825 | 1826 | 1827 | 1828 | 1829 | 1830 | 1831 | 1832 | 1833 | 1834 | 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | 1842 | 1843 | 1844 | 1845 | 1846 | 1847 | 1848 | 1849 | 1850 | 1851 | 1852 | 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 1861 | 1862 | 1863 | 1864 | 1865 | 1866 | 1867 | 1868 | 1869 | 1870 | 1871 | 1872 | 1873 | 1874 | 1875 | 1876 | 1877 | 1878 | 1879 | 1880 | 1881 | 1882 | 1883 | 1884 | 1885 | 1886 | 1887 | 1888 | 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | '; 1900 | 1901 | lcClob := lcClob || ' 1902 | 1903 | 1904 | 1905 | 1906 | 1907 | 1908 | 1909 | 1910 | 1911 | 1912 | 1913 | 1914 | 1915 | 1916 | 1917 | 1918 | 1919 | 1920 | 1921 | 1922 | 1923 | 1924 | 1925 | 1926 | 1927 | 1928 | 1929 | 1930 | 1931 | 1932 | 1933 | 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 | 1942 | 1943 | 1944 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1970 | 1971 | 1972 | 1973 | 1974 | 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 | 2030 | 2031 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2039 | 2040 | 2041 | 2042 | 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | 2049 | 2050 | '; 2051 | 2052 | RETURN lcClob; 2053 | END f_styles; 2054 | 2055 | 2056 | FUNCTION f_web_settings RETURN clob IS 2057 | BEGIN 2058 | RETURN ' 2059 | 2060 | 2061 | 2062 | '; 2063 | END f_web_settings; 2064 | 2065 | 2066 | FUNCTION f_numbering(p_doc_id pls_integer) RETURN clob IS 2067 | lcClob clob; 2068 | BEGIN 2069 | if grDoc(p_doc_id).lists.count = 0 then 2070 | RETURN null; 2071 | end if; 2072 | 2073 | lcClob := ' 2074 | 2075 | '; 2076 | 2077 | FOR t IN grDoc(p_doc_id).lists.first .. grDoc(p_doc_id).lists.last LOOP 2078 | lcClob := lcClob || ' 2079 | 2080 | 2081 | 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2094 | 2095 | 2096 | 2097 | 2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2123 | 2124 | 2125 | 2126 | 2127 | 2128 | 2129 | 2130 | 2131 | 2132 | 2133 | 2134 | 2135 | 2136 | 2137 | 2138 | 2139 | 2140 | 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | 2147 | 2148 | 2149 | 2150 | 2151 | 2152 | 2153 | 2154 | 2155 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | '; 2166 | END LOOP; 2167 | 2168 | FOR t IN grDoc(p_doc_id).lists.first .. grDoc(p_doc_id).lists.last LOOP 2169 | lcClob := lcClob || ' 2170 | '; 2171 | END LOOP; 2172 | 2173 | lcClob := lcClob || ''; 2174 | 2175 | RETURN lcClob; 2176 | 2177 | END f_numbering; 2178 | 2179 | 2180 | 2181 | 2182 | PROCEDURE p_add_clob_text(p_text clob) IS 2183 | BEGIN 2184 | gcClob := gcClob || p_text || chr(10); 2185 | END p_add_clob_text; 2186 | 2187 | 2188 | PROCEDURE p_xml_image( 2189 | p_doc_id number, 2190 | p_image_data r_image_data, 2191 | p_paragraph_yn varchar2 2192 | ) IS 2193 | 2194 | lcImageName varchar2(100) := grDoc(p_doc_id).images(p_image_data.image_id).image_name; 2195 | lcImageDesc varchar2(1000) := 'image from document'; 2196 | lnWidth pls_integer := f_unit_convert(p_doc_id, 'image', p_image_data.width); 2197 | lnHeight pls_integer := f_unit_convert(p_doc_id, 'image', p_image_data.height); 2198 | lnRotateAngle pls_integer := f_unit_convert(p_doc_id, 'image_rotate', p_image_data.rotate_angle); 2199 | lcInlineAnchor varchar2(32000) := ''; 2200 | lcPositionH varchar2(20) := to_char(f_unit_convert(p_doc_id, 'image', p_image_data.position_h)); 2201 | lcPositionV varchar2(20) := to_char(f_unit_convert(p_doc_id, 'image', p_image_data.position_v)); 2202 | 2203 | BEGIN 2204 | if p_paragraph_yn = 'Y' then 2205 | p_add_clob_text(''); 2206 | end if; 2207 | 2208 | --for anchored images 2209 | if p_image_data.inline_yn = 'N' then 2210 | lcInlineAnchor := ' 2211 | 2212 | 2213 | 2214 | ' || (CASE p_image_data.position_type_h WHEN 'align' THEN p_image_data.position_align_h ELSE lcPositionH END) || ' 2215 | 2216 | 2217 | ' || (CASE p_image_data.position_type_v WHEN 'align' THEN p_image_data.position_align_v ELSE lcPositionV END) || ' 2218 | 2219 | '; 2220 | end if; 2221 | 2222 | p_add_clob_text(' 2223 | 2224 | 2225 | ' || lcInlineAnchor || ' 2226 | 2227 | 2232 | 2233 | 2234 | 2235 | 2236 | 2237 | 2238 | 2239 | 2240 | 2241 | 2242 | 2243 | 2244 | 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | 2255 | 2256 | 2257 | 2258 | 2259 | 2260 | 2261 | 2262 | 2263 | 2264 | 2265 | 2266 | 2267 | 2268 | 2269 | 2270 | 2271 | 2272 | 2273 | 2274 | 2275 | 2276 | 2277 | 2278 | '); 2279 | 2280 | if p_paragraph_yn = 'Y' then 2281 | p_add_clob_text(''); 2282 | end if; 2283 | 2284 | END p_xml_image; 2285 | 2286 | 2287 | PROCEDURE p_xml_text( 2288 | p_doc_id pls_integer, 2289 | p_text r_text 2290 | ) IS 2291 | 2292 | CURSOR c_parts IS 2293 | SELECT 2294 | REGEXP_SUBSTR(p_text.text, '[^' || p_text.newline_character || ']+', 1, LEVEL) as text_part 2295 | FROM DUAL 2296 | CONNECT BY 2297 | REGEXP_SUBSTR(p_text.text, '[^' || p_text.newline_character || ']+', 1, LEVEL) IS NOT NULL 2298 | ; 2299 | 2300 | TYPE t_parts IS TABLE OF c_parts%ROWTYPE; 2301 | l_parts t_parts; 2302 | 2303 | 2304 | BEGIN 2305 | if p_text.text is not null then 2306 | p_add_clob_text(''); 2307 | 2308 | if not p_text.font.from_paragraph then 2309 | p_add_clob_text(''); 2310 | 2311 | p_add_clob_text(''); 2312 | p_add_clob_text(''); 2313 | p_add_clob_text(''); 2314 | p_add_clob_text(''); 2315 | 2316 | if p_text.font.bold then 2317 | p_add_clob_text(''); 2318 | end if; 2319 | 2320 | if p_text.font.italic then 2321 | p_add_clob_text(''); 2322 | end if; 2323 | 2324 | if p_text.font.underline then 2325 | p_add_clob_text(''); 2326 | end if; 2327 | 2328 | p_add_clob_text(''); 2329 | 2330 | end if; 2331 | 2332 | if p_text.replace_newline then --replace newline character with Word's actual newline tag 2333 | 2334 | OPEN c_parts; 2335 | FETCH c_parts BULK COLLECT INTO l_parts; 2336 | CLOSE c_parts; 2337 | 2338 | FOR t IN 1 .. l_parts.count LOOP 2339 | 2340 | p_add_clob_text('' || dbms_xmlgen.convert(l_parts(t).text_part) || ''); 2341 | 2342 | if t < l_parts.count then 2343 | p_add_clob_text(''); 2344 | end if; 2345 | 2346 | END LOOP; 2347 | 2348 | else 2349 | p_add_clob_text('' || dbms_xmlgen.convert(p_text.text) || ''); 2350 | 2351 | end if; 2352 | 2353 | p_add_clob_text(''); 2354 | 2355 | elsif p_text.line_break = true then 2356 | p_add_clob_text(''); 2357 | 2358 | elsif p_text.image_data.image_id is not null then 2359 | p_xml_image( 2360 | p_doc_id => p_doc_id, 2361 | p_image_data => p_text.image_data, 2362 | p_paragraph_yn => 'N' 2363 | ); 2364 | end if; 2365 | 2366 | END p_xml_text; 2367 | 2368 | 2369 | PROCEDURE p_xml_paragraph( 2370 | p_doc_id pls_integer, 2371 | p_paragraph r_paragraph 2372 | ) IS 2373 | BEGIN 2374 | --start 2375 | p_add_clob_text(''); 2376 | p_add_clob_text(''); 2377 | 2378 | --alignment 2379 | if p_paragraph.alignment_h <> 'LEFT' then 2380 | p_add_clob_text(''); 2381 | end if; 2382 | 2383 | --style (if set) 2384 | if p_paragraph.style is not null and p_paragraph.list_id is null then 2385 | p_add_clob_text(''); 2386 | end if; 2387 | 2388 | --numbering 2389 | if p_paragraph.list_id is not null then 2390 | p_add_clob_text(' 2391 | 2392 | 2393 | 2394 | '); 2395 | end if; 2396 | 2397 | p_add_clob_text(''); 2398 | 2399 | --texts 2400 | if p_paragraph.texts is not null then 2401 | FOR t IN p_paragraph.texts.first .. p_paragraph.texts.last LOOP 2402 | p_xml_text(p_doc_id, p_paragraph.texts(t)); 2403 | END LOOP; 2404 | end if; 2405 | 2406 | --end 2407 | p_add_clob_text(''); 2408 | END p_xml_paragraph; 2409 | 2410 | PROCEDURE p_xml_table( 2411 | p_doc_id pls_integer, 2412 | p_table r_table 2413 | ) IS 2414 | 2415 | lnWidth pls_integer := 0; 2416 | lcClobTop clob; 2417 | lcClobBottom clob; 2418 | lcClobLeft clob; 2419 | lcClobRight clob; 2420 | lcClobInsideH clob; 2421 | lcClobInsideV clob; 2422 | 2423 | FUNCTION f_border_text( 2424 | p_which varchar2, 2425 | p_border r_border) RETURN clob IS 2426 | lcClob clob; 2427 | BEGIN 2428 | if p_border.border_type is not null then 2429 | lcClob := ''; 2436 | end if; 2437 | 2438 | RETURN lcClob; 2439 | END; 2440 | 2441 | BEGIN 2442 | --table start 2443 | p_add_clob_text(' 2444 | 2445 | '); 2446 | 2447 | --table width 2448 | if p_table.width is null then 2449 | p_add_clob_text(''); 2450 | else 2451 | p_add_clob_text(''); 2452 | end if; 2453 | 2454 | --table borders 2455 | lcClobTop := f_border_text('top', p_table.border_top); 2456 | lcClobBottom := f_border_text('bottom', p_table.border_bottom); 2457 | lcClobLeft := f_border_text('left', p_table.border_left); 2458 | lcClobRight := f_border_text('right', p_table.border_right); 2459 | lcClobInsideH := f_border_text('insideH', p_table.border_inside_h); 2460 | lcClobInsideV := f_border_text('insideV', p_table.border_inside_v); 2461 | 2462 | if 2463 | lcClobTop is not null or 2464 | lcClobBottom is not null or 2465 | lcClobLeft is not null or 2466 | lcClobRight is not null or 2467 | lcClobInsideH is not null or 2468 | lcClobInsideV is not null 2469 | then 2470 | p_add_clob_text(' '); 2471 | p_add_clob_text(lcClobTop || lcClobBottom || lcClobLeft || lcClobRight || lcClobInsideH || lcClobInsideV); 2472 | p_add_clob_text(' '); 2473 | end if; 2474 | 2475 | 2476 | p_add_clob_text(' 2477 | '); 2478 | 2479 | --cells 2480 | FOR v IN 1 .. p_table.rows_num LOOP 2481 | p_add_clob_text(' '); 2482 | FOR s IN 1 .. p_table.columns_num LOOP 2483 | if nvl(p_table.cells(v || ',' || s).merge_h, 0) <> -1 then 2484 | p_add_clob_text(' '); 2485 | p_add_clob_text(' '); 2486 | 2487 | --width 2488 | --for horizontal merge width is calculated as sum of merged cells width 2489 | if nvl(p_table.cells(v || ',' || s).merge_h, 0) > 1 then 2490 | lnWidth := 0; 2491 | FOR t IN s .. (s + p_table.cells(v || ',' || s).merge_h - 1) LOOP 2492 | lnWidth := lnWidth + p_table.column_width(t); 2493 | END LOOP; 2494 | else 2495 | lnWidth := p_table.column_width(s); 2496 | end if; 2497 | p_add_clob_text(' '); 2498 | 2499 | --horizontal merge 2500 | if nvl(p_table.cells(v || ',' || s).merge_h, 0) > 1 then 2501 | p_add_clob_text(' '); 2502 | end if; 2503 | 2504 | --vertical merge 2505 | if p_table.cells(v || ',' || s).merge_v is not null then 2506 | p_add_clob_text(' ' || p_table.cells(v || ',' || s).merge_v); 2507 | end if; 2508 | 2509 | --vertical alignment 2510 | if p_table.cells(v || ',' || s).alignment_v <> 'TOP' then 2511 | p_add_clob_text(' '); 2512 | end if; 2513 | 2514 | --borders 2515 | lcClobTop := f_border_text('top', p_table.cells(v || ',' || s).border_top); 2516 | lcClobBottom := f_border_text('bottom', p_table.cells(v || ',' || s).border_bottom); 2517 | lcClobLeft := f_border_text('left', p_table.cells(v || ',' || s).border_left); 2518 | lcClobRight := f_border_text('right', p_table.cells(v || ',' || s).border_right); 2519 | 2520 | if lcClobTop is not null or lcClobBottom is not null or lcClobLeft is not null or lcClobRight is not null then 2521 | p_add_clob_text(' '); 2522 | p_add_clob_text(lcClobTop || lcClobBottom || lcClobLeft || lcClobRight); 2523 | p_add_clob_text(' '); 2524 | end if; 2525 | 2526 | --background color 2527 | if p_table.cells(v || ',' || s).background_color is not null then 2528 | p_add_clob_text(' '); 2529 | end if; 2530 | 2531 | 2532 | p_add_clob_text(' '); 2533 | 2534 | --add paragraph/text 2535 | p_xml_paragraph(p_doc_id, p_table.cells(v || ',' || s).paragraph); 2536 | 2537 | p_add_clob_text(' '); 2538 | end if; 2539 | END LOOP; 2540 | p_add_clob_text(' '); 2541 | END LOOP; 2542 | 2543 | --konec tabele 2544 | p_add_clob_text(''); 2545 | END p_xml_table; 2546 | 2547 | PROCEDURE p_xml_page_break(p_break r_break) IS 2548 | BEGIN 2549 | p_add_clob_text(' 2550 | 2551 | 2552 | 2553 | '); 2554 | END p_xml_page_break; 2555 | 2556 | PROCEDURE p_xml_section_break( 2557 | p_doc_id number, 2558 | p_page r_page, 2559 | p_section_type varchar2, 2560 | p_last boolean) IS 2561 | 2562 | BEGIN 2563 | --the last page at the end of document doesn't have w:p tag 2564 | if not p_last then 2565 | p_add_clob_text(' 2566 | '); 2567 | end if; 2568 | 2569 | --page data 2570 | p_add_clob_text('' || 2571 | (CASE WHEN p_section_type <> 'nextPage' THEN ' ' ELSE null END) || 2572 | (CASE WHEN p_page.header_ref is not null THEN '' ELSE null END) || 2573 | (CASE WHEN p_page.footer_ref is not null THEN '' ELSE null END) || ' 2574 | 2577 | 2578 | 2579 | 2580 | '); 2581 | 2582 | if not p_last then 2583 | p_add_clob_text(' 2584 | '); 2585 | end if; 2586 | 2587 | END p_xml_section_break; 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | PROCEDURE p_container_content( 2594 | p_doc_id number, 2595 | p_container r_container, 2596 | p_add_last_page boolean default true) IS 2597 | 2598 | lrPage r_page := grDoc(p_doc_id).default_page; 2599 | lcSectionType varchar2(50) := 'nextPage'; 2600 | 2601 | BEGIN 2602 | 2603 | FOR t IN 1 .. p_container.elements.count LOOP 2604 | 2605 | if p_container.elements(t).element_type = 'PARAGRAPH' then 2606 | p_xml_paragraph(p_doc_id, p_container.elements(t).paragraph); 2607 | 2608 | elsif p_container.elements(t).element_type = 'TABLE' then 2609 | p_xml_table(p_doc_id, p_container.elements(t).table_data); 2610 | 2611 | elsif p_container.elements(t).element_type = 'BREAK' then 2612 | 2613 | if p_container.elements(t).break_data.break_type = 'PAGE' then 2614 | p_xml_page_break(p_container.elements(t).break_data); 2615 | elsif p_container.elements(t).break_data.break_type = 'SECTION' then 2616 | p_xml_section_break(p_doc_id, lrPage, lcSectionType, false); 2617 | lrPage := p_container.elements(t).break_data.page; 2618 | lcSectionType := p_container.elements(t).break_data.section_type; 2619 | end if; 2620 | 2621 | elsif p_container.elements(t).element_type = 'IMAGE' then 2622 | p_xml_image( 2623 | p_doc_id => p_doc_id, 2624 | p_image_data => p_container.elements(t).image_data, 2625 | p_paragraph_yn => 'Y' 2626 | ); 2627 | end if; 2628 | 2629 | END LOOP; 2630 | 2631 | --last page 2632 | if p_add_last_page then 2633 | p_xml_section_break(p_doc_id, lrPage, lcSectionType, true); 2634 | end if; 2635 | 2636 | END; 2637 | 2638 | 2639 | FUNCTION f_document(p_doc_id number) RETURN clob IS 2640 | BEGIN 2641 | --main clob variabe to null 2642 | gcClob := null; 2643 | 2644 | --document start 2645 | p_add_clob_text(' 2646 | 2647 | '); 2648 | 2649 | --document content - first container is document 2650 | p_container_content(p_doc_id, grDoc(p_doc_id).containers(1)); 2651 | 2652 | --document end 2653 | p_add_clob_text(' 2654 | '); 2655 | 2656 | RETURN gcClob; 2657 | END; 2658 | 2659 | 2660 | FUNCTION f_header( 2661 | p_doc_id number, 2662 | p_header r_container) RETURN clob IS 2663 | BEGIN 2664 | --main clob variabe to null 2665 | gcClob := null; 2666 | 2667 | --header start 2668 | p_add_clob_text(' 2669 | '); 2670 | 2671 | --header content 2672 | p_container_content(p_doc_id, p_header, false); 2673 | 2674 | --header end 2675 | p_add_clob_text(''); 2676 | 2677 | RETURN gcClob; 2678 | END; 2679 | 2680 | FUNCTION f_make_document( 2681 | p_doc_id number) RETURN blob IS 2682 | 2683 | lbWord blob; 2684 | lcClob clob; 2685 | lcClobHeaderRels clob; 2686 | 2687 | BEGIN 2688 | dbms_lob.createtemporary(lbWord, true); 2689 | 2690 | --main document files 2691 | p_add_document_to_zip(lbWord, '[Content_Types].xml', f_content_types(p_doc_id)); 2692 | p_add_document_to_zip(lbWord, '_rels/.rels', f_rels); 2693 | p_add_document_to_zip(lbWord, 'docProps/app.xml', f_app); 2694 | p_add_document_to_zip(lbWord, 'docProps/core.xml', f_core(p_doc_id)); 2695 | p_add_document_to_zip(lbWord, 'word/_rels/document.xml.rels', f_document_xml_rels(p_doc_id) ); 2696 | p_add_document_to_zip(lbWord, 'word/theme/theme1.xml', f_theme); 2697 | p_add_document_to_zip(lbWord, 'word/fontTable.xml', f_font_table); 2698 | p_add_document_to_zip(lbWord, 'word/settings.xml', f_settings(p_doc_id)); 2699 | p_add_document_to_zip(lbWord, 'word/styles.xml', f_styles(p_doc_id)); 2700 | p_add_document_to_zip(lbWord, 'word/webSettings.xml', f_web_settings); 2701 | p_add_document_to_zip(lbWord, 'word/document.xml', f_document(p_doc_id) ); 2702 | 2703 | --additional documents, if used 2704 | 2705 | --numbering 2706 | lcClob := f_numbering(p_doc_id); 2707 | if lcClob is not null then 2708 | p_add_document_to_zip(lbWord, 'word/numbering.xml', lcClob); 2709 | end if; 2710 | 2711 | --headers and footers (relation XML documents too) 2712 | if grDoc(p_doc_id).images.count > 0 then 2713 | lcClobHeaderRels := f_container_xml_rels(p_doc_id); 2714 | end if; 2715 | 2716 | FOR t IN 1 .. grDoc(p_doc_id).containers.count LOOP 2717 | if grDoc(p_doc_id).containers(t).container_type = 'HEADER' then 2718 | lcClob := f_header(p_doc_id, grDoc(p_doc_id).containers(t)); 2719 | p_add_document_to_zip(lbWord, 'word/header' || grDoc(p_doc_id).containers(t).rel_id || '.xml', lcClob); 2720 | 2721 | if grDoc(p_doc_id).images.count > 0 then 2722 | p_add_document_to_zip(lbWord, 'word/_rels/header' || grDoc(p_doc_id).containers(t).rel_id || '.xml.rels', lcClobHeaderRels); 2723 | end if; 2724 | elsif grDoc(p_doc_id).containers(t).container_type = 'FOOTER' then 2725 | lcClob := f_header(p_doc_id, grDoc(p_doc_id).containers(t)); 2726 | p_add_document_to_zip(lbWord, 'word/footer' || grDoc(p_doc_id).containers(t).rel_id || '.xml', lcClob); 2727 | 2728 | if grDoc(p_doc_id).images.count > 0 then 2729 | p_add_document_to_zip(lbWord, 'word/_rels/footer' || grDoc(p_doc_id).containers(t).rel_id || '.xml.rels', lcClobHeaderRels); 2730 | end if; 2731 | end if; 2732 | END LOOP; 2733 | 2734 | --images 2735 | FOR t IN 1 .. grDoc(p_doc_id).images.count LOOP 2736 | p_add_document_to_zip(lbWord, 'word/media/' || grDoc(p_doc_id).images(t).image_name, grDoc(p_doc_id).images(t).image_file); 2737 | END LOOP; 2738 | 2739 | finish_zip(lbWord); 2740 | 2741 | RETURN lbWord; 2742 | 2743 | END; 2744 | 2745 | 2746 | PROCEDURE p_save_file( 2747 | p_document blob, 2748 | p_file_name varchar2 default 'my_document.docx', 2749 | p_folder varchar2 default 'MY_FOLDER' 2750 | ) IS 2751 | 2752 | lfFile utl_file.file_type; 2753 | lnLen pls_integer := 32767; 2754 | 2755 | BEGIN 2756 | lfFile := utl_file.fopen(p_folder, p_file_name, 'wb'); 2757 | FOR i in 0 .. trunc( (dbms_lob.getlength(p_document) - 1 ) / lnLen ) LOOP 2758 | utl_file.put_raw(lfFile, dbms_lob.substr(p_document, lnLen, i * lnLen + 1)); 2759 | END LOOP; 2760 | utl_file.fclose(lfFile); 2761 | 2762 | END p_save_file; 2763 | 2764 | PROCEDURE p_download_document( 2765 | p_doc IN OUT blob, 2766 | p_file_name varchar2, 2767 | p_disposition varchar2 default 'attachment' --values "attachment" and "inline" 2768 | ) IS 2769 | BEGIN 2770 | htp.init; 2771 | OWA_UTIL.MIME_HEADER('application/pdf', FALSE); 2772 | htp.p('Content-length: ' || dbms_lob.getlength(p_doc) ); 2773 | htp.p('Content-Disposition: ' || p_disposition || '; filename="' || p_file_name || '"' ); 2774 | OWA_UTIL.HTTP_HEADER_CLOSE; 2775 | 2776 | WPG_DOCLOAD.DOWNLOAD_FILE(p_doc); 2777 | 2778 | --free temporary lob IF it is temporary 2779 | if dbms_lob.istemporary(p_doc) = 1 then 2780 | DBMS_LOB.FREETEMPORARY(p_doc); 2781 | end if; 2782 | 2783 | --uncomment only if You plan to download the generated document from the APEX 2784 | --apex_application.stop_apex_engine; 2785 | END p_download_document; 2786 | 2787 | END zt_word; 2788 | / 2789 | -------------------------------------------------------------------------------- /package/ZT_WORD.pks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorantica/plsql-word/907749e23225470dabe0d4a0685cd4474a307a46/package/ZT_WORD.pks -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorantica/plsql-word/907749e23225470dabe0d4a0685cd4474a307a46/preview.png --------------------------------------------------------------------------------