{"id":15033918,"url":"https://github.com/sayi/poi-tl","last_synced_at":"2025-05-11T14:00:09.774Z","repository":{"id":29040139,"uuid":"32567673","full_name":"Sayi/poi-tl","owner":"Sayi","description":"Generate awesome word(docx) with template","archived":false,"fork":false,"pushed_at":"2025-04-10T15:04:20.000Z","size":102717,"stargazers_count":4685,"open_issues_count":62,"forks_count":1070,"subscribers_count":121,"default_branch":"master","last_synced_at":"2025-05-11T14:00:00.588Z","etag":null,"topics":["docx","export","java","markdown","poi","template","word"],"latest_commit_sha":null,"homepage":"https://deepoove.com/poi-tl/","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sayi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-03-20T06:47:52.000Z","updated_at":"2025-05-10T15:45:58.000Z","dependencies_parsed_at":"2023-02-16T16:00:39.571Z","dependency_job_id":"8f80bcc4-477c-4bc7-a2bc-03147164cb35","html_url":"https://github.com/Sayi/poi-tl","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Fpoi-tl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Fpoi-tl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Fpoi-tl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sayi%2Fpoi-tl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sayi","download_url":"https://codeload.github.com/Sayi/poi-tl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253576264,"owners_count":21930169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docx","export","java","markdown","poi","template","word"],"created_at":"2024-09-24T20:23:12.601Z","updated_at":"2025-05-11T14:00:09.651Z","avatar_url":"https://github.com/Sayi.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# poi-tl(poi-template-language)\n\n[![Build Status](https://app.travis-ci.com/Sayi/poi-tl.svg?branch=master)](https://app.travis-ci.com/Sayi/poi-tl) ![jdk1.6+](https://img.shields.io/badge/jdk-1.6%2B-orange.svg) ![jdk1.8](https://img.shields.io/badge/jdk-1.8-orange.svg) ![poi3.16%2B](https://img.shields.io/badge/apache--poi-3.16%2B-blue.svg) ![poi5.1.0](https://img.shields.io/badge/apache--poi-5.1.0-blue.svg) [![Gitter](https://badges.gitter.im/Sayi/poi-tl.svg)](https://gitter.im/Sayi/poi-tl?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\nA better way to generate word(docx) with template，based on Apache POI。\n\n## What is poi-tl\nFreeMarker or Velocity generates new html pages or configuration files based on text template and data. poi-tl is a Word template engine that generates **new documents** based on **Word template** and **data**.\n\nThe Word template has rich styles. Poi-tl will perfectly retain the styles in the template in the generated documents. You can also set styles for the tags. The styles of the tags will be applied to the replaced text, so you can focus on the template design. \n\npoi-tl is a *\"logic-less\"* template engine. There is no complicated control structure and variable assignment, only **tags**, some tags can be replaced with text, pictures, tables, etc., some tags will hide certain some document content, while other tags will loop a series of document content.\n\n\u003e \"Powerful\" constructs like variable assignment or conditional statements make it easy to modify the look of an application within the template system exclusively... however, at the cost of separation, turning the templates themselves into part of the application logic.\n\u003e \n\u003e [《Google CTemplate》](https://github.com/OlafvdSpek/ctemplate/blob/master/doc/guide.html)\n\npoi-tl supports **custom functions (plug-ins)**, functions can be executed anywhere in the Word template, do anything anywhere in the document is the goal of poi-tl.\n\n|Feature |Description|\n| ------------- |-------------|\n|:white_check_mark: Text |Render the tag as text|\n|:white_check_mark: Picture |Render the tag as a picture|\n|:white_check_mark: Table |Render the tag as a table|\n|:white_check_mark: Numbering |Render the tag as a numbering|\n|:white_check_mark: Chart|Bar chart (3D bar chart), column chart (3D column chart), area chart (3D area chart), line chart (3D line chart), radar chart, pie chart (3D pie Figure) and other chart rendering |\n|:white_check_mark: If Condition |Hide or display certain document content (including text, paragraphs, pictures, tables, lists, charts, etc.) according to conditions|\n|:white_check_mark: Foreach Loop | Loop through certain document content (including text, paragraphs, pictures, tables, lists, charts, etc.) according to the collection|\n|:white_check_mark: Loop table row | Loop to copy a row of the rendered table|\n|:white_check_mark: Loop table column | Loop copy and render a column of the table|\n|:white_check_mark: Loop ordered list |Support the loop of ordered list, and support multi-level list at the same time|\n|:white_check_mark: Highlight code |Word highlighting of code blocks, supporting 26 languages ​​and hundreds of coloring styles|\n|:white_check_mark: Markdown |Convert Markdown to a word document|\n|:white_check_mark: Word attachment |Insert attachment in Word|\n|:white_check_mark: Word Comments |Complete support comment, create comment, modify comment, etc.|\n|:white_check_mark: Word SDT |Complete support structured document tag |\n|:white_check_mark: Textbox |Tag support in text box|\n|:white_check_mark: Picture replacement |Replace the original picture with another picture|\n|:white_check_mark: bookmarks, anchors, hyperlinks |Support setting bookmarks, anchors and hyperlinks in documents|\n|:white_check_mark: Expression Language |Fully supports SpringEL expressions and can extend more expressions: OGNL, MVEL...|\n|:white_check_mark: Style |The template is the style, and the code can also set the style|\n|:white_check_mark: Template nesting |The template contains sub-templates, and the sub-templates then contain sub-templates|\n|:white_check_mark: Merge |Word merge Merge, you can also merge in the specified position|\n|:white_check_mark: custom functions (plug-ins) | Plug-in design, execute function anywhere in the document|\n\n## TOC\n* [Maven](#Maven)\n* [Quick start](#Quick-start)\n* [Tags](#Tags)\n  * [Text](#Text)\n  * [Picture](#Picture)\n  * [Table](#Table)\n  * [Numbering](#Numbering)\n  * [Sections](#Sections)\n    * [False Values or Empty collection](#False-Values-or-Empty-collection)\n    * [Non-False Values and Not a collection](#Non-False-Values-and-Not-a-collection)\n    * [Non-Empty collection](#Non-Empty-collection)\n  * [Nesting](#Nesting)\n* [Documentation and examples](#Documentation-and-examples)\n* [Contributing](#Contributing)\n* [FAQ](#FAQ)\n\n\n## Maven\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.deepoove\u003c/groupId\u003e\n  \u003cartifactId\u003epoi-tl\u003c/artifactId\u003e\n  \u003cversion\u003e1.12.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003e NOTE: poi-tl `1.12.x` requires POI version `5.2.2+`.\n\n## Quick start\nStart with a deadly simple example: replace `{{title}}` with \"poi-tl template engine\".\n\n1. Create a new document `template.docx`, including the content `{{title}}`\n2. TDO mode: Template + data-model = output\n\n```java\n//The core API uses a minimalist design, only one line of code is required\nXWPFTemplate.compile(\"template.docx\").render(new HashMap\u003cString, Object\u003e(){{\n         put(\"title\", \"poi-tl template engine\");\n}}).writeToFile(\"out_template.docx\");\n```\nOpen the `out_template.docx` document, everything is as you wish.\n\n## Tags\nThe tag consists of two curly braces, `{{title}}` is a tag, `{{?title}}` is also a tag, `title` is the name of the tag, and `?` identifies the type of tag. Next, we Let’s see what tag types are there.\n\n### Text\nThe text tag is the most basic tag type in the Word template. `{{name}}` will be replaced by the value of key `name` in the data model. If the key is not exist, the tag will be cleared(The program can configure whether to keep the tag or throw an exception).\n\nThe style of the text tag will be applied to the replaced text, as shown in the following example.\n\nCode:\n\n```java\nput(\"name\", \"Mama\");\nput(\"thing\", \"chocolates\");\n```\n\nTemplate:\n\n**{{name}}** always said life was like a box of {{thing}}.  \n\nOutput:\n\n**Mama** always said life was like a box of chocolates.  \n\n### Picture\nThe image tag starts with `@`, for example, `{{@logo}}` will look for the value with the key of `logo` in the data model, and then replace the tag with the image. The data corresponding to the image tag can be a simple URL or Path string, or a structure containing the width and height of the image.\n\nCode:\n```java\nput(\"watermelon\", \"assets/watermelon.png\");\nput(\"watermelon\", \"http://x/lemon.png\");\nput(\"lemon\", Pictures.ofLocal(\"sob.jpeg\", PictureType.JPEG).size(24, 24).create());\n```\n\nTemplate:\n\n```\nFruit Logo:\nwatermelon {{@watermelon}}\nlemon {{@lemon}}\nbanana {{@banana}}\n```\n\nOutput:\n\n```\nFruit Logo:\nwatermelon 🍉\nlemon 🍋\nbanana 🍌\n```\n\n### Table\nThe table tag starts with `#`, such as `{{#table}}`, it will be rendered as a Word table with N rows and N columns. The value of N depends on the data of the `table` tag.\n\nCode:\n\n```java\nput(\"table\", Tables.of(new String[][] {\n                new String[] { \"Song name\", \"Artist\" }\n            }).border(BorderStyle.DEFAULT).create());\n```\n\nTemplate:\n\n```\n{{#table}}\n```\n\nOutput:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003eSong name\u003c/td\u003e\u003ctd\u003eArtist\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n### Numbering\nThe list tag corresponds to Word's symbol list or numbered list, starting with `*`, such as `{{*number}}`.\n\nCode:\n```java\nput(\"list\", Numberings.create(\"Plug-in grammar\",\n                  \"Supports word text, pictures, table...\",\n                  \"Template, not just template, but also style template\"));\n```\n\nTemplate:\n\n```\n{{*list}}\n```\n\nOutput:\n\n```\n● Plug-in grammar\n● Supports word text, pictures, table...\n● Templates, not just templates, but also style templates\n```\n\n### Sections\nA section is composed of two tags before and after, the start tag is identified by `?`, and the end tag is identified by `/`, such as `{{?section}}` as the start tag of the sections block, `{{/section} }` is the end tag, and `section` is the name of this section.\n\nSections are very useful when processing a series of document elements. Document elements (text, pictures, tables, etc.) located in a section can be rendered zero, one or N times, depending on the value of the section.\n\n#### False Values or Empty collection\nIf the value of the section is `null`, `false` or an empty collection, all document elements located in the section will **not be displayed**, similar to the condition of the if statement is `false`.\n\nDatamodel:\n```json\n{\n  \"announce\": false\n}\n```\n\nTemplate:\n\n```\nMade it,Ma!{{?announce}}Top of the world!{{/announce}}\nMade it,Ma!\n{{?announce}}\nTop of the world!🎋\n{{/announce}}\n```\n\nOutput:\n\n```\nMade it,Ma!\nMade it,Ma!\n```\n\n#### Non-False Values and Not a collection\nIf the value of the section is not `null`, `false`, and is not a collection, all document elements in the section will be **rendered once**, similar to the condition of the if statement is `true`.\n\nDatamodel:\n```json\n{\n  \"person\": { \"name\": \"Sayi\" }\n}\n```\n\nTemplate:\n\n```\n{{?person}}\n  Hi {{name}}!\n{{/person}}\n```\n\nOutput:\n\n```\n  Hi Sayi!\n```\n\n#### Non-Empty collection\nIf the value of the section is a non-empty collection, the document elements in the section will be **looped once or N times**, depending on the size of the collection, similar to the foreach syntax.\n\nDatamodel:\n```json\n{\n  \"songs\": [\n    { \"name\": \"Memories\" },\n    { \"name\": \"Sugar\" },\n    { \"name\": \"Last Dance\" }\n  ]\n}\n```\n\nTemplate:\n\n```\n{{?songs}}\n{{name}}\n{{/songs}}\n```\n\nOutput:\n\n```\nMemories\nSugar\nLast Dance\n```\n\nIn the loop, a special tag `{{=#this}}` can be used to directly refer to the object of the current iteration.\n\nDatamodel:\n```json\n{\n  \"produces\": [\n    \"application/json\",\n    \"application/xml\"\n  ]\n}\n```\n\nTemplate:\n\n```\n{{?produces}}\n{{=#this}}\n{{/produces}}\n```\n\nOutput:\n\n```\napplication/json\napplication/xml\n```\n\n### Nesting\nNesting is the merging of another Word template in a Word template, which can be understood as import, include or word document merging, marked with `+`, such as `{{+nested}}`.\n\nCode:\n\n```java\nclass AddrModel {\n  String addr;\n  public AddrModel(String addr) {\n    this.addr = addr;\n  }\n}\n\nList\u003cAddrModel\u003e subData = new ArrayList\u003c\u003e();\nsubData.add(new AddrModel(\"Hangzhou,China\"));\nsubData.add(new AddrModel(\"Shanghai,China\"));\nput(\"nested\", Includes.ofLocal(\"sub.docx\").setRenderModel(subData).create());\n```\n\nTwo Word Template:\n\nmain.docx:\n\n```\nHello, World\n{{+nested}}\n```\n\nsub.docx:\n\n```\nAddress: {{addr}}\n```\n\nOutput:\n\n```\nHello, World\nAddress: Hangzhou,China\nAddress: Shanghai,China\n```\n\n## Documentation and examples\n\n[中文文档](http://deepoove.com/poi-tl)\n\n* [Basic Example](http://deepoove.com/poi-tl/#_%E8%BD%AF%E4%BB%B6%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3)\n* [Table Example](http://deepoove.com/poi-tl/#example-table)\n* [Sections and chart Example](http://deepoove.com/poi-tl/#example-animal)\n* [Textbox Example](http://deepoove.com/poi-tl/#example-certificate)\n* [Comment Example](http://deepoove.com/poi-tl/#plugin-comment)\n* [Example: Write Resume](http://deepoove.com/poi-tl/#example-resume)\n* [Example: Highlighting Code](http://deepoove.com/poi-tl/#plugin-highlight)\n* [Example: Convert Markdown to word](http://deepoove.com/poi-tl/#plugin-markdown)\n* [Example: Convert Swagger to word](http://deepoove.com/poi-tl/#example-swagger)\n\nFor more examples and the source code of all examples, see JUnit testcases.\n\n![](http://deepoove.com/poi-tl/demo.png)\n![](http://deepoove.com/poi-tl/demo_result.png)\n\n## Contributing\nYou can join this project in many ways, not limited to the following ways:\n* Feedback problems encountered in use\n* Share the joy of success\n* Update and improve documentation\n* Solve and discuss issues\n\n## FAQ\nSee [FAQ](http://deepoove.com/poi-tl/#_%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsayi%2Fpoi-tl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsayi%2Fpoi-tl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsayi%2Fpoi-tl/lists"}