{"id":36586947,"url":"https://github.com/developframework/kite","last_synced_at":"2026-01-12T08:04:17.594Z","repository":{"id":31175040,"uuid":"127113110","full_name":"developframework/kite","owner":"developframework","description":"json和xml的可配置生成器","archived":false,"fork":false,"pushed_at":"2024-11-14T11:31:16.000Z","size":667,"stargazers_count":7,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-04T11:08:43.230Z","etag":null,"topics":["dom4j","jackson-json","json-xml"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/developframework.png","metadata":{"files":{"readme":"README-basic.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2018-03-28T09:01:27.000Z","updated_at":"2024-11-14T11:31:20.000Z","dependencies_parsed_at":"2023-01-14T18:29:27.441Z","dependency_job_id":"e5eee567-2ae8-41a6-afbd-f4d801aaa469","html_url":"https://github.com/developframework/kite","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/developframework/kite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fkite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fkite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fkite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fkite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developframework","download_url":"https://codeload.github.com/developframework/kite/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fkite/sbom","scorecard":{"id":337184,"data":{"date":"2025-08-11","repo":{"name":"github.com/developframework/kite","commit":"c97ae20106ffa0bcd8566bf4a762b7f3a6406686"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-j288-q9x7-2f5v"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T04:58:49.539Z","repository_id":31175040,"created_at":"2025-08-18T04:58:49.539Z","updated_at":"2025-08-18T04:58:49.539Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337015,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["dom4j","jackson-json","json-xml"],"created_at":"2026-01-12T08:04:17.089Z","updated_at":"2026-01-12T08:04:17.584Z","avatar_url":"https://github.com/developframework.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 基础教程\n\n## 2. HelloWorld\n\n一个最简单的kite使用示例：\n\n```java\nKiteOptions options = new KiteOptions();\nKiteFactory kiteFactory = KiteFactoryBuilder.buildFromClasspathXml(options,\"/kite/kite-demo.xml\");\nObjectMapper objectMapper = new ObjectMapper();\nkiteFactory.useJsonFramework(new JacksonFramework(objectMapper));\nkiteFactory.useXmlFramework(new Dom4jFramework());\n\nDataModel dataModel = DataModel.singleton(\"sayHello\",\"Hello Kite!\");\n// 生成json\nString json = kiteFactory.getJsonProducer(dataModel,\"kite-demo\",\"first-view\").produce(false);\nSystem.out.println(json);\n// 生成xml\nString xml = kiteFactory.getXmlProducer(dataModel,\"kite-demo\",\"first-view\").produce(false);\nSystem.out.println(xml);\n```\n\n你需要一份Kite XML配置，位置在上述声明的/kite/kite-demo.xml：\n\n```xml\n\u003ckite-configuration xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n                    xmlns=\"https://github.com/developframework/kite/schema\"\n                    xsi:schemaLocation=\"\n\thttps://github.com/developframework/kite/schema kite-configuration.xsd\"\u003e\n\n  \u003ctemplate-package namespace=\"kite-demo\"\u003e\n\n    \u003ctemplate id=\"first-view\"\u003e\n      \u003cproperty data=\"sayHello\"/\u003e\n    \u003c/template\u003e\n\n  \u003c/template-package\u003e\n\n\u003c/kite-configuration\u003e\n```\n\n运行结果：\n\n```json\n{\"sayHello\":\"Hello Kite!\"}\n```\n\n```xml\n\u003cxml\u003e\n  \u003csay-hello\u003eHello Kite!\u003c/say-hello\u003e\n\u003c/xml\u003e\n```\n\n## 3. 概览\n\n### 3.1. java概览\n\n#### 3.1.1. DataModel\n\n\u003e com.github.developframework.kite.data.DataModel\n\nKite框架的数据模型。用于装载需要在视图中渲染的数据或函数接口实现，数据由键值对构成。接口提供存入和取出数据的方法，支持链式写法。\n\n```java\nDataModel dataModel = DataModel.singleton(\"sayHello\",\"Hello Kite!\");\n```\n\n#### 3.1.2. Expression\n\n\u003e com.github.developframework.expression.Expression\n\n是kite框架从DataModel中提取数据的表达式。不论dataModel存的是java实体类还是Map对象都可以使用表达式取值。 范例：\n\n- `student` 你可以从DataModel对象内取得名为student的对象\n- `#student` 你可以从DataModel对象内 **强制从根路径** 取得名为student的对象\n- `student.name` 你可以从DataModel对象内取得名为student的对象的name属性值\n- `students[0]` 你可以从DataModel对象内取得名为students的数组内的第1个元素\n- `student[0].name` 你可以从DataModel对象内取得名为students的数组内的第1个元素的name属性值\n\n`Expression` 的详细使用请查看独立项目[expression](https://github.com/developframework/expression)\n\n#### 3.1.3. KiteOptions\n\n\u003e com.github.developframework.kite.core.KiteOptions\n\nKite框架的配置类。\n\n```java\nKiteOptions options=new KiteOptions();\noptions.getJson().setNamingStrategy(NamingStrategy.LOWER_CASE);\n```\n\n#### 3.1.4. KiteFactory\n\n\u003e com.github.developframework.kite.core.KiteFactory\n\n类是Kite框架的构建工厂。使用Kite框架的第一步就是建立该对象。 建立该对象需要提供配置文件路径的字符串，多份配置文件可以采用字符串数组。\n\n```java\nfinal String[]xmlFile s= {\"config1.xml\",\"config2.xml\"};\nKiteFactory kiteFactory = KiteFactoryBuilder.buildFromClasspathXml(options,xmlFiles);\n```\n\n#### 3.1.5. Framework\n\n`kite-core`是一套接口，需要加入实现包才能运行，目前有以下实现包：\n\n+ `kite-jackson` 使用jackson来序列化json\n+ `kite-dom4j`使用dom4j来序列化xml\n+ `kite-fastjson`使用fastjson来序列化json\n+ `kite-gson`使用gson来序列化json\n\n```java\nkiteFactory.useJsonFramework(new JacksonFramework(objectMapper));\nkiteFactory.useXmlFramework(new Dom4jFramework());\nkiteFactory.useJsonFramework(new FastjsonFramework());\nkiteFactory.useJsonFramework(new GsonFramework());\n```\n\n#### 3.1.6. Producer\n\n\u003e com.github.developframework.kite.core.Producer\n\n接口是json字符串建造类，根据`kiteFactory.useFramework()`方法传入的`Framework`\n对象不同可以得出不同实现的Producer。\n\n```java\n// 直接生成字符串结果\nString produce(boolean pretty);\n\n// 向输出流输出结果\nvoid output(OutputStream outputStream,Charset charset,boolean pretty);\n```\n\n#### **3.1.7. 异常**\n\nKite框架的所有异常类。\n\n| 异常                              | 说明                             |\n| --------------------------------- | -------------------------------- |\n| KiteException                     | kite顶级异常                     |\n| ConfigurationSourceException      | 配置源异常                       |\n| TemplateException                 | template异常                     |\n| TemplatePackageUndefinedException | templatePackage未定义异常        |\n| KiteParseXmlException             | 配置文件解析错误异常             |\n| LinkSizeNotEqualException         | 使用link功能时数组大小不相等异常 |\n| ResourceNotUniqueException        | 资源定义不唯一异常               |\n| InvalidArgumentsException         | 无效的参数异常                   |\n\n### **3.2. XML概览**\n\n#### **3.2.1. 结构**\n\nKite configuration 文档的结构如下： \n\n```xml\n\u003ckite-configuration\u003e\n  \u003ctemplate-package namespace=\"\"\u003e\n    \u003ctemplate id=\"\"\u003e\n      \u003c!-- 定义视图内容 --\u003e\n    \u003c/template\u003e\n    \u003cfragment id=\"\"\u003e\n      \u003c!-- 定义片段内容 --\u003e\n    \u003c/fragment\u003e\n    \u003c!-- 其它template --\u003e\n  \u003c/template-package\u003e\n  \u003c!-- 其它template-package --\u003e\n\u003c/kite-configuration\u003e\n```\n\n在`\u003ckite-configuration\u003e`节点中你可以配置任意数量的`\u003ctemplate-package\u003e`，代表不同的模板包，在`\u003ctemplate-package\u003e`节点上你必须声明命名空间`namespace`\n属性，并且`namespace`是唯一的，不然会抛出`ResourceNotUniqueException`。\n\n在每个`\u003ctemplate-package\u003e`节点中你可以配置任意数量的`\u003ctemplate\u003e`。每个`\u003ctemplate\u003e`即代表了某一种json格式的视图，在`\u003ctemplate\u003e`\n节点你必须声明id属性，并且id必须是唯一的，不然会抛出`ResourceNotUniqueException`。\n\nKite configuration文档不是唯一的，Kite框架允许你拥有多份的Kite configuration配置文档，文档的加载顺序不分先后。\n\n#### **3.2.2. 标签**\n\n基本型标签\n\n- `\u003ctemplate\u003e`和`\u003cfragment\u003e`\n- `\u003cobject\u003e`\n- `\u003carray\u003e`\n- `\u003cproperty\u003e`\n- `\u003cthis\u003e`\n- `\u003cprototype\u003e`\n- `raw`\n- `\u003cxml-attribute\u003e`\n\n功能型标签\n\n- `\u003cinclude\u003e`\n- `\u003clink\u003e`\n- `\u003crelevance\u003e`\n- `\u003cobject-virtual\u003e`\n- `\u003cflat\u003e`\n- `\u003cslot\u003e`\n- `\u003cif\u003e`、 `\u003celse\u003e`\n- `\u003cswitch\u003e`、`\u003ccase\u003e`、`\u003cdefault\u003e`\n\n拓展型标签\n\n- `\u003cproperty-date\u003e`\n\n- `\u003cproperty-unixtimestamp\u003e`\n\n- `\u003cproperty-boolean\u003e`\n- `\u003cproperty-enum\u003e` `enum`\n\n##### **3.2.2.1. 基本型标签**\n\n###### a) template和fragment\n\n当你需要声明一个片段时，你将会使用到`\u003cfragment\u003e`标签\n\n当你需要声明一个模板时，你将会使用到`\u003ctemplate\u003e`标签\n\n  ```xml\n\u003cfragment id=\"\"\u003e\n\n\u003c/fragment\u003e\n\n\u003ctemplate id=\"\"\u003e\n\n\u003c/template\u003e\n  ```\n\n| 属性     | 功能                                                         | 是否必须 |\n| -------- | ------------------------------------------------------------ | -------- |\n| id       | 声明模板编号，在命名空间中唯一                               | 是       |\n| data     | 取值表达式                                                   | 否       |\n| extend   | 声明继承的kite和端口，格式为**namespace.id**（namespace不填时默认为当前template所在的namespace） | 否       |\n| xml-root | 生成xml时的根节点名称                                        | 否       |\n\ntemplate包含`\u003carray\u003e`节点的所有属性\n\ntemplate和fragment的区别：\n\n+ template是fragment的子类，它也是一个片段\n+ fragment不能被直接调用，**只能include或被extend**，而template可以直接被调用\n\n###### b) object\n\n当你需要构建一个对象结构时，你将会使用到`\u003cobject\u003e`标签\n\n```xml\n\u003cobject data=\"\"\u003e\n\n\u003c/object\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n| converter       | 类型转换器全限定类名或expression表达式。              | 否       |\n\n###### c) array\n\n当你需要构建一个数组结构时，你将会使用到`\u003carray\u003e`标签\n\n```xml\n\u003carray data=\"\"\u003e\n\n\u003c/array\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n| converter       | 类型转换器全限定类名或expression表达式                | 否       |\n| map             | MapFunction的实现类全名或Expression表达式             | 否       |\n| xml-item        | 生成xml时，子节点数组项的节点名称                     | 否       |\n| limit           | 取前若干个元素                                        | 否       |\n| comparator      | Comparator比较器接口实现类表达式                      | 否       |\n| null-empty      | true时表示表达式取的值为null时设为空数组，默认为false | 否       |\n\n`\u003carray\u003e`标签可以没有子标签，这时表示数组为基本类型数组，如果是对象将会调用它的`toString()`方法。\n\n###### d) property\n\n当你需要构建一个普通属性结构时， 你将会使用到`\u003cproperty\u003e`标签。\n\n```xml\n\u003cproperty data=\"\"/\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| converter       | 类型转换器全限定类名或expression表达式                | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n| xml-cdata       | 生成xml时是否使用`\u003c![CDATA[  ]]\u003e`，默认false          | 否       |\n\n###### e) this\n\n指代节点本身值\n\n```xml\n\u003cthis alias=\"\"\u003e\n\n\u003c/this\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| alias           | 别名，你可以重新定义显示名                            | 是       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n| converter       | 类型转换器全限定类名或expression表达式                | 否       |\n| xml-cdata       | 生成xml时是否使用`\u003c![CDATA[  ]]\u003e`，默认false          | 否       |\n\n###### f) prototype\n\n原型实体构建结构，即使用实现框架自己的序列化功能， 你将会使用到`\u003cprototype\u003e`标签\n\n```xml\n\u003cprototype data=\"\"/\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| converter       | 类型转换器全限定类名或expression表达式                | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n\n###### g) raw\n\n使用raw字符串构建结构， 你将会使用到`\u003craw\u003e`标签。\n\n```xml\n\u003craw data=\"\"/\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| converter       | 类型转换器全限定类名或expression表达式                | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n\n###### h) xml-attribute\n\n在输出xml时，提供配置xml节点的属性值。\n\n```xml\n\u003cxml-attribute data=\"\"/\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式                                            | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n\n##### **3.2.2.2. 功能型标签**\n\n###### a) include\n\nKite框架提供模块化设计json结构视图的功能。在一个`\u003ctemplate\u003e`标签中你可以采用`\u003cinclude\u003e`标签来导入其它的`\u003ctemplate\u003e`\n的结构内容，从而实现模块化单元分解\n\n```xml\n\u003cinclude id=\"\" namespace=\"\"/\u003e\n```\n\n| 属性      | 功能                                       | 是否必须 |\n| --------- | ------------------------------------------ | -------- |\n| id        | 需要导入的template id                      | 是       |\n| namespace | template的命名空间，不填默认为当前命名空间 | 否       |\n\n###### b) link\n\n该标签用于实现一对一链接对象功能\n\n```xml\n\u003clink data=\"\"\u003e\n\n\u003c/link\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式，**data必须指代一个List或array类型的对象** | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n\n###### c) relevance\n\n该标签用于实现一对多关联功能。\n\n```xml\n\u003crelevance data=\"\" rel=\"\"\u003e\n\n\u003c/relevance\u003e\n```\n\n| 属性            | 功能                                                  | 是否必须 |\n| --------------- | ----------------------------------------------------- | -------- |\n| data            | 取值表达式，**data必须指代一个List或array类型的对象** | 是       |\n| alias           | 别名，你可以重新定义显示名                            | 否       |\n| naming-strategy | 命名策略，默认FRAMEWORK                               | 否       |\n| rel             | 关联判定器全限定类名或expression表达式                | 是       |\n| null-hidden     | true时表示表达式取的值为null时隐藏该节点，默认为false | 否       |\n| map             | KiteConverter的实现类全名或Expression表达式。         | 否       |\n| null-empty      | true时表示表达式取的值为null时设为空数组，默认为false | 否       |\n| merge-parent    | 单个值时可以拼接到父级                                | 否       |\n\n###### d) object-virtual\n\n该标签用于虚拟对象结构\n\n```xml\n\u003cobject-virtual alias=\"\"\u003e\n\n\u003c/object-virtual\u003e\n```\n\n| 属性  | 功能 | 是否必须 |\n| ----- | ---- | -------- |\n| alias | 别名 | 是       |\n\n###### d) flat\n\n该标签用于扁平化对象结构，把子层节点拼接到父层\n\n```xml\n\u003cflat data=\"\"\u003e\n\n\u003c/flat\u003e\n```\n\n| 属性      | 功能                                   | 是否必须 |\n| --------- | -------------------------------------- | -------- |\n| data      | 取值表达式                             | 是       |\n| converter | 类型转换器全限定类名或expression表达式 | 否       |\n\n###### f) slot\n\n此标签位置作为子`\u003ctemplate\u003e`的插槽位置。和template的`extend`结合使用\n\n```xml\n\u003ctemplate id=\"\" extend=\"\"\u003e\n  \u003cslot/\u003e\n\u003c/template\u003e\n```\n\n###### g) if  else\n\n分支结构标签\n\n```xml\n\u003cif condition=\"\"\u003e\n\n\u003c/if\u003e\n\u003celse\u003e\n\n\u003c/else\u003e\n```\n\n| 属性      | 功能                                 | 是否必须 |\n| --------- | ------------------------------------ | -------- |\n| condition | 条件接口实现类全名或Expression表达式 | 是       |\n\n###### h) switch  case  default\n\n分支结构标签\n\n```xml\n\u003cswitch check-data=\"\"\u003e\n\t\u003ccase test=\"\"\u003e\u003c/case\u003e\n\t\u003ccase test=\"\"\u003e\u003c/case\u003e\n\t\u003cdefault\u003e\u003c/default\u003e\n\u003c/switch\u003e\n```\n\n| 属性       | 功能                             | 是否必须 |\n| ---------- | -------------------------------- | -------- |\n| check-data | 取值表达式                       | 否       |\n| test       | CaseTestFunction接口实现类表达式 | 是       |\n\n\n##### **3.2.2.3. 拓展型标签**\n\n###### a) property-date\n\n该标签拓展于`\u003cproperty\u003e`，针对时间日期类型，使用`pattern`属性来格式化日期时间\n\n| 拓展属性 | 功能                                              | 是否必须 |\n| -------- | ------------------------------------------------- | -------- |\n| pattern  | 格式化模板字符串，不填默认为\"yyyy-MM-dd HH:mm:ss\" | 否       |\n\n支持的时间日期类型：\n\n- java.util.Date\n- java.sql.Date\n- java.sql.Time\n- java.sql.Timestamp\n- (JDK8) java.time.LocalDate\n- (JDK8) java.time.LocalDateTime\n- (JDK8) java.time.LocalTime\n- (JDK8) java.time.Instant\n\n###### b) property-unixtimestamp\n\n该标签拓展于`\u003cproperty\u003e`，针对时间日期类型，可以将时间日期类型转化为unix时间戳格式显示。可支持的时间日期类型同`\u003cproperty-date\u003e`。\n\n###### c) property-boolean\n\n该标签拓展于`\u003cproperty\u003e`，可以将数字类型（short、int、long）变为boolean型，非0值为true，0值为false。\n\n###### d) property-enum\n\n该标签拓展于`\u003cproperty\u003e`，可以将值映射成另一个固定值。\n\n## \u003ca name=\"chapter4\"\u003e**4. 基本使用**\u003c/a\u003e\n\n模型声明（以下各小节示例代码均使用这些模型实体类）：\n\n```java\n// 公司类 Company.java\n@Data\n@RequiredArgsConstructor\npublic class Company {\n  // 公司ID\n  private final Integer companyId;\n  // 公司名称\n  private final String companyName;\n}\n```\n\n```java\n// 部门 Department.java   一个公司多个部门\n@Data\n@RequiredArgsConstructor\npublic class Department {\n  // 部门ID\n  private final Integer departmentId;\n  // 部门名称\n  private final String departmentName;\n}\n```\n\n```java\n// 员工 Staff.java   一个部门多个\n@Data\n@RequiredArgsConstructor\npublic class Staff {\n  // 员工ID\n  private final Integer staffId;\n  // 部门ID\n  private final Integer departmentId;\n  // 员工姓名\n  private final String staffName;\n  // 性别\n  private final Gender gender;\n  // 生日\n  private final LocalDate birthday;\n\n  public enum Gender {\n    MALE, FEMALE, UNKNOWN\n  }\n}\n```\n\n对应的kite configuration文件配置\n\n```xml\n\u003c!-- 忽略kite-configuration --\u003e\n\u003ctemplate-package namespace=\"kite-demo\"\u003e\n\n  \u003ctemplate id=\"company-info\" data=\"company\"\u003e\n    \u003cproperty data=\"companyId\"/\u003e\n    \u003cproperty data=\"companyName\"/\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate id=\"department-info\" data=\"department\"\u003e\n    \u003cproperty data=\"departmentId\"/\u003e\n    \u003cproperty data=\"companyId\"/\u003e\n    \u003cproperty data=\"departmentName\"/\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate id=\"staff-info\" data=\"staff\"\u003e\n    \u003cproperty data=\"staffId\"/\u003e\n    \u003cproperty data=\"departmentId\"/\u003e\n    \u003cproperty data=\"staffName\"/\u003e\n    \u003cproperty data=\"gender\"/\u003e\n    \u003cproperty-date data=\"birthday\"/\u003e\n  \u003c/template\u003e\n\n\u003c/template-package\u003e\n```\n\n伪造数据\n\n```java\npublic final class DemoDataMock {\n\n  public static Company[] mockCompanies() {\n    return new Company[]{\n            new Company(1, \"XX科技公司\"),\n            new Company(2, \"YY网络公司\")\n    };\n  }\n\n  public static Department[] mockDepartments() {\n    return new Department[]{\n            new Department(11, 1, \"技术部\"),\n            new Department(12, 2, \"运营部\"),\n            new Department(13, 1, \"财务部\"),\n            new Department(14, 2, \"事业部\")\n    };\n  }\n\n  public static Staff[] mockStaffs() {\n    return new Staff[]{\n            new Staff(111, 11, \"小张\", Staff.Gender.MALE, LocalDate.of(1988, 2, 3)),\n            new Staff(112, 12, \"小王\", Staff.Gender.FEMALE, LocalDate.of(1992, 12, 6)),\n            new Staff(113, 13, \"小李\", Staff.Gender.FEMALE, LocalDate.of(1995, 6, 15)),\n            new Staff(114, 14, \"小孙\", Staff.Gender.UNKNOWN, LocalDate.of(1983, 11, 8)),\n            new Staff(115, 12, \"小郑\", Staff.Gender.FEMALE, LocalDate.of(1986, 9, 5)),\n            new Staff(116, 13, \"小钱\", Staff.Gender.MALE, LocalDate.of(1984, 10, 1)),\n            new Staff(117, 14, \"小潘\", Staff.Gender.FEMALE, LocalDate.of(1990, 12, 12)),\n    };\n  }\n\n  public static Integer[] mockScores() {\n    return new Integer[]{70, 85, 93, 87, 81, 94, 97, 86};\n  }\n}\n```\n\n### 4.1. 简单输出模型对象\n\n```java\n// 初始化kiteFactory 后续不再赘述\nfinal ObjectMapper objectMapper = new ObjectMapper();\nobjectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);\nfinal JavaTimeModule javaTimeModule = new JavaTimeModule();\njavaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(\"yyyy-MM-dd\")));\nobjectMapper.registerModules(javaTimeModule);\nfinal KiteFactory kiteFactory = KiteFactoryBuilder.buildFromClasspathXml(new KiteOptions(),\"kite/kite-demo.xml\");\nkiteFactory.useJsonFramework(new JacksonFramework(objectMapper));\nkiteFactory.useXmlFramework(new Dom4jFramework());\n\nDataModel dataModel = DataModel.singleton(\"company\",DemoDataMock.mockCompanies()[0]);\nString json = kiteFactory.getJsonProducer(dataModel,\"kite-demo\",\"company-info\").produce(false);\nString xml = kiteFactory.getXmlProducer(dataModel,\"kite-demo\",\"company-info\").produce(false);\nSystem.out.println(json);\nSystem.out.println(xml);\n```\n\n执行结果：\n\n```json\n{\n  \"company_id\": 1,\n  \"company_name\": \"XX科技公司\"\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003ccompany-id\u003e1\u003c/company-id\u003e\n  \u003ccompany-name\u003eXX科技公司\u003c/company-name\u003e\n\u003c/xml\u003e\n```\n\n### 4.2. 使用alias修改显示名称\n\n```xml\n\u003ctemplate id=\"company-info\" data=\"company\"\u003e\n  \u003cproperty data=\"companyId\" alias=\"id\"/\u003e\n  \u003cproperty data=\"companyName\" alias=\"name\"/\u003e\n\u003c/template\u003e\n```\n\n```json\n{\n  \"id\": 1,\n  \"name\": \"XX科技公司\"\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003cid\u003e1\u003c/id\u003e\n  \u003cname\u003eXX科技公司\u003c/name\u003e\n\u003c/xml\u003e\n```\n\n### 4.3. naming-strategy命名策略\n\n\u003e com.github.developframework.kite.core.strategy.KitePropertyNamingStrategy\n\njson节点和xml节点名称的命名策略扩展，继承接口\n\n```java\npublic interface KitePropertyNamingStrategy {\n\n  /**\n   属性最终显示名称\n   */\n  String propertyDisplayName(Framework\u003c?\u003e framework, String name);\n}\n```\n\n传入的name是data的变量名称，通过接口方法改写得出最终要显示的名称。\n\nKite内置接口实现：\n\n+ **FRAMEWORK** JacksonKitePropertyNamingStrategy 用实现框架配置的策略命名，比如Jackson ObjectMapper设置的PropertyNamingStrategy\n+ **MIDDLE_LINE** MiddleLineKitePropertyNamingStrategy 中划线命名策略，AbCd =\u003e ab-cd\n+ **UNDERLINE** UnderlineXmlKitePropertyNamingStrategy 下划线xml命名策略，AbCd =\u003e ab_cd\n+ **LOWDER_CASE** LowerCaseKitePropertyNamingStrategy 全小写命名策略， AbCd =\u003e abcd\n+ **ORIGINAL** OriginalKitePropertyNamingStrategy 什么都不做，使用原名\n\n可在`KiteOptions`里分别给json和xml的序列化设置全局命名策略\n\n```java\nfinal KiteOptions options=new KiteOptions();\n        options.getJson().setNamingStrategy(NamingStrategy.UNDERLINE);\n        options.getXml().setNamingStrategy(NamingStrategy.MIDDLE_LINE);\n```\n\n也可以在实际的模板里某个内容节点上配置`naming-strategy` 属性强制使用某个策略\n\n```xml\n\u003ctemplate id=\"test-naming-strategy\"\u003e\n  \u003cobject data=\"myCompany\" naming-strategy=\"ORIGINAL\"\u003e\n    \u003cproperty data=\"companyId\" naming-strategy=\"MIDDLE_LINE\"/\u003e\n    \u003cproperty data=\"companyName\" naming-strategy=\"UNDERLINE\"/\u003e\n  \u003c/object\u003e\n\u003c/template\u003e\n```\n\n```json\n{\n  \"myCompany\": {\n    \"company-id\": 1,\n    \"company_name\": \"XX科技公司\"\n  }\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003cmyCompany\u003e\n    \u003ccompany-id\u003e1\u003c/company-id\u003e\n    \u003ccompany_name\u003eXX科技公司\u003c/company_name\u003e\n  \u003c/myCompany\u003e\n\u003c/xml\u003e\n```\n\n### 4.4. property扩展\n\n#### 4.4.1 使用property-date格式化日期时间\n\n该标签可以格式化时间\n\n```xml\n\u003cproperty data=\"birthday\"/\u003e\n```\n\n替换为\n\n```xml\n\u003cproperty-date data=\"birthday\" pattern=\"yyyy年MM月dd日\"/\u003e\n```\n\n运行结果：\n\n```json\n{\n  \"birthday\": \"1995年01月01日\"\n}\n```\n\n#### 4.4.2 使用property-unixtimestamp输出时间戳\n\n该标签可以使日期时间类型转化成时间戳形式输出。\n\n```java\ndataModel.putData(\"datetime\", LocalDateTime.of(2016, 1, 1, 0, 0, 0));\n```\n\n```json\n{\"datetime\" : 1451577600}\n```\n\n#### 4.4.3 使用property-boolean转换\n\n该标签可以把非0数字转换成true，0转换成false\n\n```java\nDataModel dataModel = new DataModel();\ndataModel.putData(\"number1\", 1);\ndataModel.putData(\"number2\", 0);\n```\n\n```json\n{\"number1\" : true, \"number2\" : false}\n```\n\n#### 4.4.4 使用property-enum映射\n\n该标签可以把值映射成另一个固定值，该标签不仅可以处理枚举类型，字符串或者基本类型都可以处理\n\n```xml\n\u003cproperty-enum data=\"gender\"\u003e\n  \u003cenum value=\"MALE\" text=\"男\"/\u003e\n  \u003cenum value=\"FEMALE\" text=\"女\"/\u003e\n\u003c/property-enum\u003e\n```\n\n```java\nDataModel dataModel=DataModel.singleton(\"gender\",Staff.Gender.MALE);\n```\n\n```json\n{\n  \"gender\": \"男\"\n}\n```\n\n### 4.5. null-hidden和null-empty\n\n所有的内容节点可以用`null-hidden`来隐藏data指代对象值为null的节点\n\n`\u003carray\u003e`标签可以用`null-empty`属性把data指代对象值为null的节点设为空数组\n\n```xml\n\u003ctemplate id=\"test-array-null\"\u003e\n  \u003carray data=\"array\" alias=\"null-array\"/\u003e\n  \u003carray data=\"array\" alias=\"empty-array\" null-empty=\"true\"/\u003e\n  \u003carray data=\"array\" alias=\"null-hidden-array\" null-hidden=\"true\"/\u003e\n\u003c/template\u003e\n```\n\n```java\nDataModel dataModel=DataModel.singleton(\"array\",null);\n```\n\n```json\n{\n  \"null-array\": null,\n  \"empty-array\": []\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003cnull-array/\u003e\n  \u003cempty-array/\u003e\n\u003c/xml\u003e\n```\n\n### 4.6. object array template\n\n```xml\n\u003ctemplate id=\"company-info\"\u003e\n  \u003cobject data=\"company\"\u003e\n    \u003cproperty data=\"companyId\"/\u003e\n    \u003cproperty data=\"companyName\"/\u003e\n  \u003c/object\u003e\n\u003c/template\u003e\n```\n\n利用`\u003cobject\u003e`标签构造一个对象结构\n\n```java\nDataModel dataModel=DataModel.singleton(\"company\",DemoDataMock.mockCompanies()[0]);\n```\n\n```json\n{\n  \"company\": {\n    \"company_id\": 1,\n    \"company_name\": \"XX科技公司\"\n  }\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003ccompany\u003e\n    \u003ccompany-id\u003e1\u003c/company-id\u003e\n    \u003ccompany-name\u003eXX科技公司\u003c/company-name\u003e\n  \u003c/company\u003e\n\u003c/xml\u003e\n```\n\n利用`array` 标签构造一个数组结构：\n\n```xml\n\u003ctemplate id=\"company-info\"\u003e\n  \u003carray data=\"companies\" xml-item=\"company\"\u003e\n    \u003cproperty data=\"companyId\"/\u003e\n    \u003cproperty data=\"companyName\"/\u003e\n  \u003c/array\u003e\n\u003c/template\u003e\n```\n\n```java\nDataModel dataModel=DataModel.singleton(\"company\",DemoDataMock.mockCompanies());\n```\n\n```json\n{\n  \"companies\": [\n    {\n      \"company_id\": 1,\n      \"company_name\": \"XX科技公司\"\n    },\n    {\n      \"company_id\": 2,\n      \"company_name\": \"YY网络公司\"\n    }\n  ]\n}\n```\n\n```xml\n\u003cxml\u003e\n  \u003ccompanies\u003e\n    \u003ccompany\u003e\n      \u003ccompany-id\u003e1\u003c/company-id\u003e\n      \u003ccompany-name\u003eXX科技公司\u003c/company-name\u003e\n    \u003c/company\u003e\n    \u003ccompany\u003e\n      \u003ccompany-id\u003e2\u003c/company-id\u003e\n      \u003ccompany-name\u003eYY网络公司\u003c/company-name\u003e\n    \u003c/company\u003e\n  \u003c/companies\u003e\n\u003c/xml\u003e\n```\n\n或者直接把data设定在`\u003ctemplate\u003e` 标签上，Kite框架会自动识别data对应的数据是否是数组或List。\n\n```xml\n\u003ctemplate id=\"company-info\" data=\"company\" xml-item=\"company\" xml-root=\"companies\"\u003e\n  \u003cproperty data=\"companyId\"/\u003e\n  \u003cproperty data=\"companyName\"/\u003e\n\u003c/template\u003e\n```\n\n当data指代的对象是Array或Collection时生成数组结构\n\n```json\n[\n  {\n    \"company_id\": 1,\n    \"company_name\": \"XX科技公司\"\n  },\n  {\n    \"company_id\": 2,\n    \"company_name\": \"YY网络公司\"\n  }\n]\n```\n\n```xml\n\u003ccompanies\u003e\n  \u003ccompany\u003e\n    \u003ccompany-id\u003e1\u003c/company-id\u003e\n    \u003ccompany-name\u003eXX科技公司\u003c/company-name\u003e\n  \u003c/company\u003e\n  \u003ccompany\u003e\n    \u003ccompany-id\u003e2\u003c/company-id\u003e\n    \u003ccompany-name\u003eYY网络公司\u003c/company-name\u003e\n  \u003c/company\u003e\n\u003c/companies\u003e\n```\n\n当data指代的对象是单个对象时生成对象结构\n\n```json\n{\n  \"company_id\": 1,\n  \"company_name\": \"XX科技公司\"\n}\n```\n\n```xml\n\u003ccompanies\u003e\n  \u003ccompany-id\u003e1\u003c/company-id\u003e\n  \u003ccompany-name\u003eXX科技公司\u003c/company-name\u003e\n\u003c/companies\u003e\n```\n\n### **4.7. prototype使用原型实体**\n\n使用`\u003cprototype\u003e` 标签可以使用原生的框架转换成json，以下展示使用Jackson作为实现框架\n\n```xml\n\u003ctemplate id=\"staff-info\"\u003e\n  \u003cprototype data=\"staff\"/\u003e\n\u003c/template\u003e\n```\n\n以下加入Jackson的注解达到序列化效果\n\n```java\n@Data\n@RequiredArgsConstructor\npublic class Staff {\n\n  // 员工ID\n  private final Integer staffId;\n  // 部门ID  忽略该属性\n  @JsonIgnore\n  private final Integer departmentId;\n  // 员工姓名  改写属性名\n  @JsonProperty(\"name\")\n  private final String staffName;\n  // 性别\n  private final Gender gender;\n  // 生日\n  private final LocalDate birthday;\n\n  public enum Gender {\n    MALE, FEMALE, UNKNOWN\n  }\n}\n```\n\n```json\n{\n  \"staff\": {\n    \"staff_id\": 111,\n    \"gender\": \"MALE\",\n    \"birthday\": \"1988-02-03\",\n    \"name\": \"小张\"\n  }\n}\n```\n\n更多注解使用请参考jackson-annotations文档。\n\n### 4.8. raw原文本\n\n使用`\u003craw\u003e`来添加原文本对象，内部使用具体实现框架来反序列化的。\n\n```xml\n\u003ctemplate id=\"test-raw\"\u003e\n  \u003craw data=\"companyJson\" alias=\"company\"/\u003e\n\u003c/template\u003e\n```\n\n```json\nString rawJson = \"{\\\"company_id\\\":1,\\\"company_name\\\":\\\"XX科技公司\\\"}\";\nDataModel dataModel = DataModel.singleton(\"companyJson\", rawJson);\n```\n\n```json\n{\n  \"company\": {\n    \"company_id\": 1,\n    \"company_name\": \"XX科技公司\"\n  }\n}\n```\n\n## 5. 日志\n\nKite框架使用slf4j-api日志接口，提供内部日志打印功能。可以使用log4j或者logback打印日志。\n以下示例使用logback\n\n```xml\n\u003cconfiguration scan=\"true\" scanPeriod=\"60 seconds\" debug=\"false\"\u003e\n  \u003ccontextName\u003ekite-log\u003c/contextName\u003e\n  \u003cappender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\"\u003e\n    \u003cencoder\u003e\n      \u003cpattern\u003e%d{HH:mm:ss.SSS} %-5level - %msg%n\u003c/pattern\u003e\n    \u003c/encoder\u003e\n  \u003c/appender\u003e\n  \u003clogger name=\"com.github.developframework.kite\" level=\"INFO\" additivity=\"false\"\u003e\n    \u003cappender-ref ref=\"STDOUT\" /\u003e\n  \u003c/logger\u003e\n\u003c/configuration\u003e\n```\n\n项目启动日志：\n\n```\n09:29:07.753 【Kite】已加载配置源“/kite/kite-demo.xml”\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopframework%2Fkite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevelopframework%2Fkite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopframework%2Fkite/lists"}