Documentation ¶
Index ¶
- Constants
- Variables
- func GetDefaultTextTags() []string
- func GetDefaultVoidElements() []string
- func NewTemplate(m *tplManager, name string, node *Node) *htmlTemplate
- func NewTplManager() *tplManager
- type Attr
- type BaseScanner
- type CodeScanner
- type CodeToken
- type CodeTokenKind
- type HtmlScanner
- type Node
- type Parser
- type Pos
- type Tag
- type Token
- type TokenKind
Examples ¶
Constants ¶
const ( DefaultTagPrefix = "t:" // 默认的标签名前缀 DefaultAttrPrefix = ":" // 默认的属性名前缀 )
Variables ¶
var ( // ErrDuplicatedTplName 重复的模板名称 ErrDuplicatedTplName = fmt.Errorf("duplicated template name") // ErrTplNotFound 模板未找到 ErrTplNotFound = fmt.Errorf("template not found") // ErrNilTag 找不到 tag 信息 ErrNilTag = fmt.Errorf("unexpected nil tag") )
var ErrAttrValueExpected = fmt.Errorf("attribute value expected")
ErrAttrValueExpected 没有属性值
var ErrUnexpectedEOF = errors.New("unecpected EOF")
ErrUnexpectedEOF 非预期的 EOF. 读取标签过程中遇到 EOF 时会返回
Functions ¶
func GetDefaultVoidElements ¶
func GetDefaultVoidElements() []string
GetDefaultVoidElements 默认的空标签 不含闭合斜线 不含内容
func NewTemplate ¶
NewTemplate 构造一个模板实例
Types ¶
type Attr ¶
type Attr struct { Name string // 属性名 NameStart Pos // 开始位置 NameEnd Pos // 结束位置 Value *string // 属性值 如果有 ValueStart Pos // 开始位置 ValueEnd Pos // 结束位置 ValueTokens []*CodeToken // 解析后的属性值 }
Attr 属性
type BaseScanner ¶
type BaseScanner struct {
// contains filtered or unexported fields
}
BaseScanner 词法扫描器
type CodeScanner ¶
type CodeScanner struct { *BaseScanner // contains filtered or unexported fields }
CodeScanner 代码解析器
func NewCodeScanner ¶
func NewCodeScanner(start Pos, s string) *CodeScanner
NewCodeScanner 新建代码解析器实例
func (*CodeScanner) GetAllTokens ¶
func (t *CodeScanner) GetAllTokens() ([]*CodeToken, error)
GetAllTokens 获取所有解析后的代码词法单元
func (*CodeScanner) NextToken ¶
func (t *CodeScanner) NextToken() (*CodeToken, error)
NextToken 解析下一个词法单元
type CodeToken ¶
type CodeToken struct { Kind CodeTokenKind Start Pos End Pos Value string Tree parser.IExpressionContext }
CodeToken 代码词法单元
type CodeTokenKind ¶
type CodeTokenKind int
CodeTokenKind 代码词法单元类型
const ( Error CodeTokenKind = iota // "Hello, ${name}" BegEnd // 开始或结束的引号 Literal // 字面量 CodeStart // ${ CodeValue // 代码内容 CodeEnd // } )
type HtmlScanner ¶
type HtmlScanner struct { *BaseScanner // contains filtered or unexported fields }
HtmlScanner HTML 词法解析器
Example ¶
package main import ( "fmt" "strings" "code.gopub.tech/logs/pkg/arg" "code.gopub.tech/tpl/html" ) func main() { s := html.NewHtmlScanner(strings.NewReader(`<!DOCTYPE html> <html lang = "zh"> <head> <meta charset="UTF-8"> <title>标题</title> </head> <body> <script>/*<script*/</script> </body> </html>`)) tokens, err := s.GetAllTokens() if err != nil { panic(err) } fmt.Printf("tokens: %v", arg.JSON(tokens)) }
Output: tokens: [{"Kind":1,"Value":"\u003c!DOCTYPE html\u003e","Start":{"Line":1,"Column":1},"End":{"Line":1,"Column":16},"Tag":{"Name":"!DOCTYPE","Attrs":[{"Name":"html","NameStart":{"Line":1,"Column":11},"NameEnd":{"Line":1,"Column":15},"Value":null,"ValueStart":{"Line":0,"Column":0},"ValueEnd":{"Line":0,"Column":0},"ValueTokens":null}]}},{"Kind":2,"Value":"\n","Start":{"Line":1,"Column":16},"End":{"Line":2,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003chtml lang = \"zh\"\u003e","Start":{"Line":2,"Column":1},"End":{"Line":2,"Column":19},"Tag":{"Name":"html","Attrs":[{"Name":"lang","NameStart":{"Line":2,"Column":7},"NameEnd":{"Line":2,"Column":11},"Value":"\"zh\"","ValueStart":{"Line":2,"Column":14},"ValueEnd":{"Line":2,"Column":18},"ValueTokens":null}]}},{"Kind":2,"Value":"\n","Start":{"Line":2,"Column":19},"End":{"Line":3,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003chead\u003e","Start":{"Line":3,"Column":1},"End":{"Line":3,"Column":7},"Tag":{"Name":"head","Attrs":null}},{"Kind":2,"Value":"\n\t","Start":{"Line":3,"Column":7},"End":{"Line":4,"Column":5},"Tag":null},{"Kind":1,"Value":"\u003cmeta charset=\"UTF-8\"\u003e","Start":{"Line":4,"Column":5},"End":{"Line":4,"Column":27},"Tag":{"Name":"meta","Attrs":[{"Name":"charset","NameStart":{"Line":4,"Column":11},"NameEnd":{"Line":4,"Column":18},"Value":"\"UTF-8\"","ValueStart":{"Line":4,"Column":19},"ValueEnd":{"Line":4,"Column":26},"ValueTokens":null}]}},{"Kind":2,"Value":"\n ","Start":{"Line":4,"Column":27},"End":{"Line":5,"Column":5},"Tag":null},{"Kind":1,"Value":"\u003ctitle\u003e","Start":{"Line":5,"Column":5},"End":{"Line":5,"Column":12},"Tag":{"Name":"title","Attrs":null}},{"Kind":2,"Value":"标题","Start":{"Line":5,"Column":12},"End":{"Line":5,"Column":14},"Tag":null},{"Kind":1,"Value":"\u003c/title\u003e","Start":{"Line":5,"Column":14},"End":{"Line":5,"Column":22},"Tag":{"Name":"/title","Attrs":null}},{"Kind":2,"Value":"\n","Start":{"Line":5,"Column":22},"End":{"Line":6,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003c/head\u003e","Start":{"Line":6,"Column":1},"End":{"Line":6,"Column":8},"Tag":{"Name":"/head","Attrs":null}},{"Kind":2,"Value":"\n","Start":{"Line":6,"Column":8},"End":{"Line":7,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003cbody\u003e","Start":{"Line":7,"Column":1},"End":{"Line":7,"Column":7},"Tag":{"Name":"body","Attrs":null}},{"Kind":2,"Value":"\n\t","Start":{"Line":7,"Column":7},"End":{"Line":8,"Column":5},"Tag":null},{"Kind":1,"Value":"\u003cscript\u003e","Start":{"Line":8,"Column":5},"End":{"Line":8,"Column":13},"Tag":{"Name":"script","Attrs":null}},{"Kind":2,"Value":"/*\u003cscript*/","Start":{"Line":8,"Column":13},"End":{"Line":8,"Column":24},"Tag":null},{"Kind":1,"Value":"\u003c/script\u003e","Start":{"Line":8,"Column":24},"End":{"Line":8,"Column":33},"Tag":{"Name":"/script","Attrs":null}},{"Kind":2,"Value":"\n","Start":{"Line":8,"Column":33},"End":{"Line":9,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003c/body\u003e","Start":{"Line":9,"Column":1},"End":{"Line":9,"Column":8},"Tag":{"Name":"/body","Attrs":null}},{"Kind":2,"Value":"\n","Start":{"Line":9,"Column":8},"End":{"Line":10,"Column":1},"Tag":null},{"Kind":1,"Value":"\u003c/html\u003e","Start":{"Line":10,"Column":1},"End":{"Line":10,"Column":8},"Tag":{"Name":"/html","Attrs":null}}]
func NewHtmlScanner ¶
func NewHtmlScanner(r io.Reader) *HtmlScanner
NewHtmlScanner 新建一个词法解析器实例 默认设置的文本 tag 有:["script", "style", "textarea", "title"]
func (*HtmlScanner) GetAllTokens ¶
func (t *HtmlScanner) GetAllTokens() ([]*Token, error)
GetAllTokens 解析所有词法单元
func (*HtmlScanner) NextToken ¶
func (t *HtmlScanner) NextToken() (*Token, error)
NextToken 解析一个词法单元
func (*HtmlScanner) SetAttrPrefix ¶
func (s *HtmlScanner) SetAttrPrefix(prefix string) *HtmlScanner
func (*HtmlScanner) SetTextTags ¶
func (s *HtmlScanner) SetTextTags(tagNames []string) *HtmlScanner
SetTextTags 设置只能包含文本不能包含子标签的标签 如 ["script", "style", "textarea", "title"] 读取这些标签的文本内容时,允许包含 "</tagName" 但一旦遇到 "</tagName>" 会认为结束 如 <script>/*</script.*/</script>
type Node ¶
type Node struct { Token *Token // 节点内容 End *Token // 结束标签(如有) Parent *Node // 父节点 Children []*Node // 子节点 }
Node 文档树节点
func (*Node) GetChildrenWithoutHeadTailBlankText ¶
GetChildrenWithoutHeadTailBlankText 获取子节点 但不要第一个和最后一个空白节点(如果不是空白节点就要) 用于
<template :define="name"> <p>blabla</p> </template>
insert 和 replace 时去除多余的空白
func (*Node) GetNextSibling ¶
GetNextSibling 获取下一个兄弟节点 可用于获取 :range 节点之后的空白文本节点
func (*Node) GetPreviousSibling ¶
GetPreviousSibling 获取前一个兄弟节点
func (*Node) GetPreviousSiblingTag ¶
GetPreviousSiblingTag 获取前一个 tag 节点 可用于 :else 之前是否 :if 检测
type Parser ¶
type Parser struct {
VoidElements []string
}
Parser 文档树解析器
func (*Parser) ParseTokens ¶
ParseTokens 将 tokens 解析为文档树
func (*Parser) SetVoidElements ¶
SetVoidElements 设置空标签
type Tag ¶
Tag <标签> 如果是结束标签则 Name 以 / 开头
func (*Tag) IsSelfClose ¶
IsSelfClose 是否是自闭合标签 注意 <meta> 这种 void 标签不属于自闭合标签 只有 <name/> 这种以 / 结尾的才算 包含三种:无属性的 <name/>; 无属性值的 <name />; 有属性值的 <name k=v/>
func (*Tag) SortedAttr ¶
SortedAttr 对属性排序 指令属性排在前 各指令属性中再按 if, range, remove 顺序 其他属性按出现先后不变