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

 

  • 只在特定领域使用的语言 如 HTML Gradle SQL

  1. 特点

  •  计算器变成语言

  1. 具有语言的表达能力

  2. 有限的表达能力

  3. 关注某个特定领域

下面来写一段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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安果移不动

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值