html

package
v0.0.0-...-5e93b50 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 26, 2024 License: MIT Imports: 17 Imported by: 2

Documentation

Index

Examples

Constants

View Source
const (
	DefaultTagPrefix  = "t:" // 默认的标签名前缀
	DefaultAttrPrefix = ":"  // 默认的属性名前缀
)

Variables

View Source
var (
	// ErrDuplicatedTplName 重复的模板名称
	ErrDuplicatedTplName = fmt.Errorf("duplicated template name")
	// ErrTplNotFound 模板未找到
	ErrTplNotFound = fmt.Errorf("template not found")
	// ErrNilTag 找不到 tag 信息
	ErrNilTag = fmt.Errorf("unexpected nil tag")
)
View Source
var ErrAttrValueExpected = fmt.Errorf("attribute value expected")

ErrAttrValueExpected 没有属性值

View Source
var ErrUnexpectedEOF = errors.New("unecpected EOF")

ErrUnexpectedEOF 非预期的 EOF. 读取标签过程中遇到 EOF 时会返回

Functions

func GetDefaultTextTags

func GetDefaultTextTags() []string

GetDefaultTextTags 默认的只包含文本的标签

func GetDefaultVoidElements

func GetDefaultVoidElements() []string

GetDefaultVoidElements 默认的空标签 不含闭合斜线 不含内容

func NewTemplate

func NewTemplate(m *tplManager, name string, node *Node) *htmlTemplate

NewTemplate 构造一个模板实例

func NewTplManager

func NewTplManager() *tplManager

NewTplManager 新建一个 HTML 模板管理器

Types

type Attr

type Attr struct {
	Name        string       // 属性名
	NameStart   Pos          // 开始位置
	NameEnd     Pos          // 结束位置
	Value       *string      // 属性值 如果有
	ValueStart  Pos          // 开始位置
	ValueEnd    Pos          // 结束位置
	ValueTokens []*CodeToken // 解析后的属性值
}

Attr 属性

func (*Attr) Evaluate

func (a *Attr) Evaluate(input exp.Scope) (string, error)

Evaluate 在给定的作用域上计算属性值

func (*Attr) String

func (a *Attr) String() string

String 打印输出 不保证格式 debug only

func (*Attr) WithAssign

func (a *Attr) WithAssign(input exp.Scope) (map[string]any, error)

WithAssign 解析 :with="name := ${value}" 赋值属性 返回解析后的变量名,变量值 :with="name := ${value} ; b:=${1}"

type BaseScanner

type BaseScanner struct {
	// contains filtered or unexported fields
}

BaseScanner 词法扫描器

func NewBaseScanner

func NewBaseScanner(r io.Reader) *BaseScanner

NewBaseScanner 构造函数

func (*BaseScanner) Err

func (b *BaseScanner) Err(format string, a ...any) error

Err 记录解析错误

func (*BaseScanner) NextRune

func (b *BaseScanner) NextRune() error

NextRune 读取下一个字符

func (*BaseScanner) SetPos

func (b *BaseScanner) SetPos(p Pos) *BaseScanner

SetPos 设置位置

func (*BaseScanner) UnRead

func (b *BaseScanner) UnRead()

UnRead 回退一个字符

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 代码词法单元

func (*CodeToken) String

func (t *CodeToken) String() string

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

func (n *Node) GetChildrenWithoutHeadTailBlankText() (result []*Node)

GetChildrenWithoutHeadTailBlankText 获取子节点 但不要第一个和最后一个空白节点(如果不是空白节点就要) 用于

<template :define="name">
  <p>blabla</p>
</template>

insert 和 replace 时去除多余的空白

func (*Node) GetNextSibling

func (n *Node) GetNextSibling() (next *Node)

GetNextSibling 获取下一个兄弟节点 可用于获取 :range 节点之后的空白文本节点

func (*Node) GetPreviousSibling

func (n *Node) GetPreviousSibling() (pre *Node)

GetPreviousSibling 获取前一个兄弟节点

func (*Node) GetPreviousSiblingTag

func (n *Node) GetPreviousSiblingTag() (pre *Node)

GetPreviousSiblingTag 获取前一个 tag 节点 可用于 :else 之前是否 :if 检测

func (*Node) IsBlankText

func (n *Node) IsBlankText() bool

IsBlankText 当前节点是否是空白文本

type Parser

type Parser struct {
	VoidElements []string
}

Parser 文档树解析器

func NewParser

func NewParser() *Parser

NewParser 新建一个解析器实例

func (*Parser) ParseTokens

func (p *Parser) ParseTokens(tokens []*Token) (*Node, error)

ParseTokens 将 tokens 解析为文档树

func (*Parser) SetVoidElements

func (p *Parser) SetVoidElements(s []string) *Parser

SetVoidElements 设置空标签

type Pos

type Pos = exp.Pos

type Tag

type Tag struct {
	Name  string
	Attrs []*Attr
	// contains filtered or unexported fields
}

Tag <标签> 如果是结束标签则 Name 以 / 开头

func (*Tag) AddAttr

func (t *Tag) AddAttr(attr *Attr) error

AddAttr 保存属性

func (*Tag) AttrMap

func (t *Tag) AttrMap() map[string]*Attr

AttrMap 构造属性 Map 用于快速查找

func (*Tag) IsClose

func (t *Tag) IsClose() bool

IsClose 是否是闭合标签 包含两种:正常的闭合标签 </name>, 自闭合标签 <name />

func (*Tag) IsSelfClose

func (t *Tag) IsSelfClose() bool

IsSelfClose 是否是自闭合标签 注意 <meta> 这种 void 标签不属于自闭合标签 只有 <name/> 这种以 / 结尾的才算 包含三种:无属性的 <name/>; 无属性值的 <name />; 有属性值的 <name k=v/>

func (*Tag) SortedAttr

func (t *Tag) SortedAttr(prefix string) []*Attr

SortedAttr 对属性排序 指令属性排在前 各指令属性中再按 if, range, remove 顺序 其他属性按出现先后不变

func (*Tag) String

func (t *Tag) String() string

type Token

type Token struct {
	Kind  TokenKind // 类型
	Value string    // 内容
	Start Pos       // 开始位置
	End   Pos       // 结束位置
	Tag   *Tag      // 如果是标签
}

Token 词法单元

func (*Token) IsBlankText

func (t *Token) IsBlankText() bool

func (*Token) String

func (t *Token) String() string

type TokenKind

type TokenKind int

TokenKind 类型

const (
	TokenKindError   TokenKind = iota // 错误
	TokenKindTag                      // Tag 类型
	TokenKindText                     // Text 文本类型
	TokenKindComment                  // 注释
	TokenKindCDATA                    // CDATA
)

func (TokenKind) String

func (p TokenKind) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL