> 文档中心 > kotlin 高阶函数 DSL 手撕HTML

kotlin 高阶函数 DSL 手撕HTML


kotlin 高阶函数 DSL 解析HTML

文章目录

  • kotlin 高阶函数 DSL 解析HTML
  • 前言
  • 一、kotlin 高阶函数 解析 HTML
  • 二、使用 DSL 解析HTML

前言

使用纯代码 加 注释的方式,可以更快的理解源码
如果你喜欢,请点个赞,后期会不断的深入讲解


一、kotlin 高阶函数 解析 HTML

先看一张图

在这里插入图片描述

代码如下

import java.io.File//   面向对象思维, 设计 类的关系,(依赖倒转原则)面向对象 而 不面向细节private interface Element { // 元素顶级接口    /**     * buffer    拼接所有元素     * indent    缩进效果     */    fun run(builder: StringBuilder, indent: String)}// 从最简单的 text 文本开始private class TextElement(val text: String) : Element {    override fun run(builder: StringBuilder, indent: String) {// 缩进后,显示文本内容 builder.append("$indent$text\n")    }}//    开始写复杂的部分    private open class Tag(val tagName: String) : Element {      //tagName 文本的 Element 如       //    集合,每一个元素都是 Element    val elements = arrayListOf<Element>()    //    Map 集合, 每一个元素 key = 元素名, Value = 属性对应的值    val attribute = hashMapOf<String, String>()    override fun run(builder: StringBuilder, indent: String) {     // 被 toString触发// 缩进  builder.append("$indent<$tagName${renderAttributes()}>\n") for (element in elements) {     element.run(builder, indent + "  ") }//   闭合 builder.append("$indent</$tagName>\n")    }    //    属性拼装  href = "https://blog.csdn.net/u010755471"//    null   没有属性    private fun renderAttributes(): String? { val builder = StringBuilder() for (key in attribute.keys) {//     空格: <a href     builder.append(" $key=\"${attribute[key]}\"") } return builder.toString()    }    override fun toString(): String { val stringBuilder = StringBuilder() run(stringBuilder, "")     // 参数1: stringBuilder 方便组装HTML 参数,  参数二:indent 不要缩进 return stringBuilder.toString()    }}private open class TagClass(tagName: String) : Tag(tagName) {    operator fun String.unaryPlus() {// 运算符重载 + elements.add(TextElement(this))  // elements.add    }    operator fun String.unaryMinus() {// 运算符重载 - elements += TextElement(this)    }}//   第一个中转站 Htmlprivate class Html : TagClass("html") {    fun head(action: Head.() -> Unit) { val newHead = Head() newHead.action() elements += newHead      //  添加进数组    }    fun body(action: Body.() -> Unit) { val newBody = Body("body") newBody.action() elements += newBody    }}//   Head 中转站private class Head : TagClass("head") {    fun title(action: Title.() -> Unit) { val newTitle = Title() newTitle.action() elements.add(newTitle)    }}//    Body 中转站private open class Body(tagName: String) : TagClass(tagName = tagName) {    fun h1(action: H1.() -> Unit) { val newH1 = H1() newH1.action() elements += newH1    }    fun p(action: P.() -> Unit) { val newP = P() newP.action() elements += newP    }    open fun a(href: String, action: A.() -> Unit) { val newA = A() newA.href = href newA.action() elements += newA    }}//    h1 中转站private class H1 : Body("h1") {}//     P 中转站private class P : Body("p") {    fun b(action: B.() -> Unit) { val newB = B() newB.action() elements += newB    }    override fun a(href: String, action: A.() -> Unit) { val newA = A() newA.href = href newA.action() elements += newA    }    fun ul(action: Ul.() -> Unit) { val newUl = Ul() newUl.action() elements += newUl    }}//     A 中转站private class A : Body("a") {    var href: String get() = attribute["href"]!! set(value) {     attribute["href"] = value }}//     P 中转站private class B : Body("b") {}//     Ul 中转站private class Ul : Body("ul") {    fun li(action: Li.() -> Unit) { val newLi = Li() newLi.action() elements.add(newLi)    }}//     Li 中转站private class Li : Body("li") {}//     Title 中转站private class Title : TagClass("title") {}private fun html(action: Html.() -> Unit): Html {    val html = Html()    html.action()    return html}fun main(args: Array<String>) {    val names = listOf("张三", "大漂亮", "王美丽")    val result = html { // this == 第一个中转站 { head body 。。 }     head { // this == head中转站 { title }  title { +"使用 Kotlin 进行 HTML 编码" }     }     body { // this == body中转站 { h1 p a p }  h1 { // this == h1中转站 { 未知 }  }  p { -"此格式可用作 HTML 的替代标记" }  // 具有属性和文本内容的元素  a(href = "https://blog.csdn.net/u010755471") { -"不爱学习的猪的博客" }  // 混合内容  p {      -"Derry老师来了"      b { -"Derry是谁" }      -"文本。有关更多信息,请参阅"      a(href = "https://blog.csdn.net/u010755471") { -"不爱学习的猪的博客" }      -"Derry的项目"  }  p { -"一些文字" }  // 从命令行参数生成的内容  p {      -"命令行参数是:"      ul { // this == UL中转站 { li 子标签  }   for (name in names)li { -name } // this == LI中转站      }  }     } }    println(result)    val file = File("/Users/Documents/Android leaning work/kotlinleaning04/testHtml.html")    file.writeText(result.toString())}

二、使用 DSL 解析HTML

先来张图

在这里插入图片描述

源码如下:

import java.io.File//   定义一个节点接口interface Node {    fun create(): String}// 中转站class BlockNode(val name: String) : Node {    val children = ArrayList<Node>()     // 节点集合:  html head body    private val properties = hashMapOf<String, Any>()   //属性集合:style='color: white; font-family: Microsoft YaHei'    override fun create(): String { return """<$name ${properties.map { "${it.key}='${it.value}'" }.joinToString(" ")}>${children.joinToString ( "" ){it.create()}}</$name"""    }    operator fun String.invoke(action: BlockNode.() -> Unit){ val stringNode = BlockNode(this) stringNode.action() this@BlockNode.children += stringNode    }    operator fun String.invoke(value: Any){ this@BlockNode.properties[this] = value    }    operator fun String.unaryPlus(){ val stringNode = StringNode("$this &sbsp; &sbsp;") this@BlockNode.children += stringNode    }}class StringNode(private val value: String) : Node {    override fun create(): String { return value    }}fun html(action: BlockNode.() -> Unit): BlockNode {    val blockNode = BlockNode("html")    blockNode.action()    return blockNode}fun BlockNode.head(action: BlockNode.() -> Unit) {    val head = BlockNode("head")    head.action()    children += head}fun BlockNode.body(action: BlockNode.() -> Unit) {    val body = BlockNode("body")    body.action()    children += body}fun main() {    val htmlContent = html { // this持有中转站BlockNode head { // this持有中转站BlockNode     // String.invoke(Any)     "meta" { "charset"("UTF-8") } } body {     "div" {  "style"(      """      width: 666px;height: 666px;line-height: 600px;background-color: #F00;      text-align: center      """.trimIndent()  )  "span" {      "style"(   """   color: white;   font-family: Microsoft YaHei   """.trimIndent()      )      +"你好 HTML DSL!!"      +"我就是我,不一样的烟火"      +"像我这样牛逼的人"      +"世界上还有几人"  }     } }    }.create() // 用户调用create函数,我就组装    println(htmlContent)    File("/Users/tiger/Documents/Android leaning work/kotlinleaning04/ttt.html") .writeText(htmlContent)}