-
只在特定领域使用的语言 如 HTML Gradle SQL
-
特点
-
计算器变成语言
-
具有语言的表达能力
-
有限的表达能力
-
关注某个特定领域
下面来写一段html DSL
新建文件
Node.kt
package com.yzdzy.kotlin.chapter6
interface Node {
fun render(): String
}
新建Tag.kt
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
新建Main.kt
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
Tag("html").apply {
proerties["id"] = "HtmlId"
children.add(Tag("head"))
}.render().let(::println)
}
效果打印
<html id="HtmlId"><head></head></html>
继续优化
新建 Nodes.kt
package com.yzdzy.kotlin.chapter6
fun html(block: Tag.() -> Unit): Tag {
return Tag("html").apply {
block(this)
}
}
修改Main
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
html {
proerties["id"] = "HtmlId"
children.add(Tag("head"))
}.render().let(::println)
}
运行 结果不变
<html id="HtmlId"><head></head></html>
继续优化Tag
新增对String得扩展
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//对String 扩展 “id”:("HtmlId")
operator fun String.invoke(value: String) {
}
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
修改main代码
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
html {
"id"("HtmlId")
proerties["id"] = "HtmlId"
children.add(Tag("head"))
}.render().let(::println)
}
修改Tag.kt 完善 String扩展
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//对String 扩展 “id”:("HtmlId")
operator fun String.invoke(value: String) {
//proerties[this] =id
proerties[this] = value
}
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
运行main
效果不变
<html id="HtmlId"><head></head></html>
继续优化
修改Tag 新增对head得扩展
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//对String 扩展 “id”:("HtmlId")
operator fun String.invoke(value: String) {
//proerties[this] =id
proerties[this] = value
}
//对head 操作。
operator fun String.invoke(block:Tag.()->Unit){
children.add(Tag(this).apply(block))
}
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
修改main 并运行
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
html {
"id"("HtmlId")
"head"{
"id"("headId")
}
}.render().let(::println)
}
<html id="HtmlId"><head id="headId"></head></html>
继续优化
修改
Nodes.kt
package com.yzdzy.kotlin.chapter6
fun html(block: Tag.() -> Unit): Tag {
return Tag("html").apply {
block(this)
}
}
class StringNode(val content: String) : Node {
override fun render() = content
}
修改 Tag
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//对String 扩展 “id”:("HtmlId")
operator fun String.invoke(value: String) {
//proerties[this] =id
proerties[this] = value
}
//对head 操作。
operator fun String.invoke(block:Tag.()->Unit){
children.add(Tag(this).apply(block))
}
//对 + 号重写
operator fun String.unaryPlus() {
children.add(StringNode(this))
}
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
修改main
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
html {
"id"("HtmlId")
"head"{
"id"("headId")
}
"body"{
"a"{
"href"("https://www.kotliner.cn")
+ "Kotlin 中文博客"
}
}
}.render().let(::println)
}
查看效果
<html id="HtmlId"><head id="headId"></head><body><a href="https://www.kotliner.cn">Kotlin 中文博客</a></body></html>
最终优化。。没加div标签哈
Main.kt
package com.yzdzy.kotlin.chapter6
fun main(args: Array<String>) {
html {
"id"("HtmlId")
head {
"id"("headId")
}
body {
id = "bodyUId"
`class` = "bodyClass"
"a"{
"href"("https://www.yzdzy.com")
+ "优质的资源"
}
}
}.render().let(::println)
}
新建 MapDelegate.kt
package com.yzdzy.kotlin.chapter6
import java.util.concurrent.locks.ReadWriteLock
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class MapDelegate(val map: MutableMap<String, String>) : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return map[property.name] ?: ""
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
map[property.name] = value
}
}
Nodes.kt
package com.yzdzy.kotlin.chapter6
fun html(block: Tag.() -> Unit): Tag {
return Tag("html").apply {
block(this)
}
}
fun Tag.head(block: Head.() -> Unit) {
this@head + Head().apply(block)
}
fun Tag.body(block: Body.() -> Unit) {
this@body + Body().apply(block)
}
class StringNode(val content: String) : Node {
override fun render() = content
}
class Head : Tag("head")
class Body : Tag("body") {
var id by MapDelegate(proerties)
var `class` by MapDelegate(proerties)
}
Tag.kt
package com.yzdzy.kotlin.chapter6
import java.lang.StringBuilder
open class Tag(val name: String) : Node {
val children = ArrayList<Node>();
val proerties = HashMap<String, String>();
//对String 扩展 “id”:("HtmlId")
operator fun String.invoke(value: String) {
//proerties[this] =id
proerties[this] = value
}
//对head 操作。
operator fun String.invoke(block: Tag.() -> Unit) {
children.add(Tag(this).apply(block))
}
//对 + 号重写
operator fun String.unaryPlus() {
children.add(StringNode(this))
}
//对Nodes.kt Tag.head Tag.body 运算符得+做操作
operator fun plus(node:Node) {
children.add(node)
}
//<html id="htmlId" style=""><head></head><body></body></html>
override fun render(): String {
return StringBuilder()
.append("<")
.append(name)
.let { stringBuilder ->
if (this.proerties.isNotEmpty()) {
stringBuilder.append(" ")
this.proerties.forEach {
stringBuilder.append(it.key)
stringBuilder.append("=\"")
stringBuilder.append(it.value)
stringBuilder.append("\"")
}
}
stringBuilder
}
.append(">")
.let { stringBuilder ->
children.map(Node::render).map(stringBuilder::append)
stringBuilder
}
.append("</$name>")
.toString()
}
}
运行结果
<html id="HtmlId"><head id="headId"></head><body id="bodyUId"class="bodyClass"><a href="https://www.yzdzy.com">优质的资源</a></body></html>