0
点赞
收藏
分享

微信扫一扫

【35】kotlin DSL的概念与自制DSL HTML页面

捌柒陆壹 2023-03-10 阅读 78


只在特定领域使用的语言 如 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>

举报

相关推荐

0 条评论