tinydom

package module
v0.0.0-...-5f8dd16 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2018 License: BSD-3-Clause Imports: 7 Imported by: 0

README

Overview

Build Status GoDoc Language License codecov goreport

tinydom是一个非验证的,轻量级的,经过充分测试的go语言(golang)xml流的dom构造器。

tinydom简介

tidydom使用golang的encoding/xml标准库作为底层XML文本流的解析器。使用tinydom提供的接口可以实现简单的XML文件的读取和生成。 tinydom借鉴了tinyxml2的接口设计技巧,提供了丰富的XML元素的查找手段。

如何使用

接口定义

一个XML文档由XMLDocumentXMLElementXMLTextXMLCommentXMLProcInstXMLDirective这几种类型的节点组成。

  • XMLDocument是一个XML文档的根节点。
  • XMLElement是XML文档的基本节点元素,一个XMLElement可以含有多个XMLAttribute
  • XMLText是XML的文本元素,支持CDATA和XML字符转义。
  • XMLComment表示的是XML的注释,是<!---->之间的部分。
  • XMLProcInst表示的是<??>之间的部分,一般出现在xml文档的声明部分。
  • XMLDirective表示的是<!>之间的部分,一般为DTD。
  • XNLNode是所有这些节点的共同基础,XMLNode提供了丰富的节点元素遍历手段。
  • XMLVisitor提供了一种XML对象的元素遍历机制。
  • XMLHandle的作用是简化代码编写工作,使用XMLHandle将减少很多判空处理的代码(if nil == xxx {}),活用XMLHandle可以让我们的编码工作事半功倍,代码也更加健壮。

加载文档

tinydom.LoadDocument用于从一个文件流或者字符流读取XML数据,并构建出tinydom.XMLDocument对象,一般用于读取XML文件的场景。

import "tinydom"
doc, err := tinydom.LoadDocument(strings.NewReader(s))

FirstChildElementLastChildElementPrevElementNextElement这几个函数,主要是为了方便查找XMLElement元素, 大部分情况下我们建立XML文档的DOM模型就是为了对XMLElement进行访问。

xmlstr := `
<books>
    <book><name>The Moon</name><author>Tom</author></book>
    <book><name>Go west</name><author>Suny</author></book>
<books>
`
doc, _ := tinydom.LoadDocument(strings.NewReader(xmlstr))
elem1 := doc.FirstChildElement("books").FirstChildElement("book").FirstChildElement("name")
fmt.Println(elem1.Text()) //	The Moon
elem2 := doc.FirstChildElement("books").FirstChildElement("book").LastChildElement("author")
fmt.Println(elem2.Text()) //	Suny

查找节点

  • 获取子节点

FirstChildLastChild这两个函数用于获取某个节点的子节点,不管节点是什么类型都可以用这两个函数获取到.

FirstChildElementLastChildElement这两个函数专用于查找指定的Element节点,如果指定了name参数,那么只查找指定名字的子Element节点.

  • 获取相邻节点

PrevNext这两个函数用于查找当前节点的前一个或者后一个兄弟节点.

PrevElementNextElement这两个函数用于查找当前节点的上一个或者下一个Element节点.我们同样可以通过指定这两个函数的name参数来查找执行名字的Element节点.

  • 获取父节点

Parent函数直接获取当前节点的父节点.

  • 节点类型转换

我们提供了一堆的转换函数:

ToElement() XMLElement

ToText() XMLText

ToComment() XMLComment

ToDocument() XMLDocument

ToProcInst() XMLProcInst

ToDirective() XMLDirective

  • 获取节点属性

XMLElement接口提供了多个获取属性的函数:

查找: FindAttribute(name string) XMLAttribute

遍历: ForeachAttribute(callback func(attribute XMLAttribute) int) int

属性个数统计: AttributeCount() int

直接获取属性字符串: Attribute(name string, def string) string

文档的遍历

ParentFirstChildLastChildPrevNext用于使我们可以方便地在XML的DOM树中游走。 下面这个函数可以用于对一个doc进行遍历:

func walk(m int , rootNode tinydom.XMLNode) {
    if nil == rootNode {
        return
    }
    for child := rootNode.FirstChild(); nil != child; child = child.Next() {
        fmt.Println(strings.Repeat(" ", m), child.Value())
        walk(m + 1, child)
    }
}

您可以这样调用:

walk(0, doc)

还有一个更好的替代方式是使用tinydom.XMLVisitor接口对文档中的元素进行遍历,可参见代码中tinydom.XMLVisitor的接口定义。

新建文档

tinydom.NewDocument用于在内存中生成DOM,一般用于生成XML文件。

tinydom提供了一系列的NewXXX方法用于创建各种不同类型的节点:

tinydom.NewText(document XMLDocument, text string) XMLText

tinydom.NewComment(document XMLDocument, comment string) XMLComment

tinydom.NewElement(document XMLDocument, name string) XMLElement

tinydom.NewProcInst(document XMLDocument, target string, inst string) XMLProcInst

tinydom.NewDirective(document XMLDocument, directive string) XMLDirective

而下面这些函数用于将任意类型的节点加入当前节点,或者对节点进行删除操作:

  • 将node添加为本节点的最后一个子节点(最常用):InsertEndChild(node XMLNode) XMLNode

  • 将node添加为本节点的第一个子节点:InsertFirstChild(node XMLNode) XMLNode

  • 将addThis添加到本节点的后面:InsertBack(addThis XMLNode) XMLNode

  • 将addThis添加到本节点的前面:InsertFront(addThis XMLNode) XMLNode

  • 删除本节点所有的子节点:DeleteChildren()

  • 删除本节点的指定的子节点:DeleteChild(node XMLNode)

  • 将本节点从其所属的document中拆除:Split()

我们也可以对节点的属性进行操作:

  • 新增属性或者修改属性值: SetAttribute(name string, value string) XMLAttribute

  • 删除属性: DeleteAttribute(name string) XMLAttribute

  • 删除所有属性: ClearAttributes()

下面的代码创建了一个XML文档:

doc := tinydom.NewDocument()
books := doc.InsertEndChild(tinydom.NewElement(doc, "books"))
book := books.InsertEndChild(tinydom.NewElement(doc, "book"))
name := book.InsertEndChild(tinydom.NewElement(doc, "name"))
name.InsertEndChild(tinydom.NewText(doc, "The Moon"))
doc.InsertEndChild(tinydom.NewProcInst(doc, "xml", `version="1.0" encoding="UTF-8"`))

我们可以使用tinydom.XMLDocumentAccept方法来将这个XML文档输出:

doc.Accept(tinydom.NewSimplePrinter(os.Stdout, tinydom.PrettyPrint))

输出

tinydom采用了访问者模式(参见tinydom.XMLVisitor接口)来对文档的所有节点进行遍历,tinydom.XMLVisitortinydom.XMLDocumentAccept方法结合基本可以输出满足我们大多数场景的XML文档输出任务.我们完全可以使用该机制自己定制文档输出格式.

不过,为了方便大多数使用场景,tinydom仍然提供了一个专用于打印的visitor.下面这行代码用于直接向屏幕打印XML文档:

doc.Accept(tinydom.NewSimplePrinter(os.Stdout, tinydom.PrettyPrint))

tinydom.NewSimplePrinter的接口如下:

func NewSimplePrinter(writer io.Writer, options PrintOptions) XMLVisitor

tinydom.NewSimplePrinter的第二个参数用于控制输出格式:

type PrintOptions struct {
    Indent        []byte //  缩进前缀,只允许填写tab或者空白,如果Indent长度为0表示折行但是不缩进,如果Indent为null表示不折行
    TextWrapWidth int    //  超过多长才强制换行
}

为简化编码tinydom也提供了两种缺省的PrintOptions:

  • tinydom.PrintPretty 优美打印: 节点输出自动折行,并按4个空格缩进
  • tinydom.PrintStream 流式打印: 节点输出不带换行,除非Text部分有换行

对于自定义XML文档输出模式而言,处理XML字符转义是个麻烦,因为你必须处理一些细节.但tinydom也可在这方面帮助你.tinydom提供了 tinydom.EscapeAttributetinydom.EscapeText来方便处理属性和XMLText中的转义字符.您也可以使用golang自带 的xml.EscapeText,只是这个函数做了更多的转义,会导致文档更难阅读和编辑.

XML字符转义

受益于go的xml库,tinydom也支持XML字符转义,使用tinydom在读写xml的数据的时候不需要关注XML转义字符,tinydom自动会处理好,可参考下面的例子:

xmlstr :=
    `<talks>
        <talk from="bill" to="tom">[&amp;&apos;&quot;&gt;&lt;] are the xml escape chars? </talk>
        <talk from="tom" to="bill">yes, that is right</talk>
     </talks>
    `
doc, _ := tinydom.LoadDocument(strings.NewReader(xmlstr))
talk := doc.FirstChildElement("talks").FirstChildElement("talk").Text()
fmt.Print(talk) //  [&'"><] are the xml escape chars?

xml文档输出时,可使用tinydom.EscapeAttributetinydom.EscapeText来对字符进行转义.

CDATA

只有XMLText对象才涉及到CDATA,可以通过XMLText获取到CDATA对象的数据,tinydom能够自动识别CDATA,但是将DOM对象序列化成字符串时,除非节点指定了CDATA属性,否则会直接转义。

xmlstr := `<content><![CDATA[<example>This is ok in cdata text</example>]]></content>`
doc, _ := tinydom.LoadDocument(strings.NewReader(xmlstr))
content := doc.FirstChildElement("content")
fmt.Println("\nRead CDATA:", content.Text())
fmt.Println("\nNormal Print:")
doc.Accept(tinydom.NewSimplePrinter(os.Stdout))
text := content.FirstChild().ToText()
text.SetCDATA(true)
fmt.Println("\nSpecial as CDATA:")
doc.Accept(tinydom.NewSimplePrinter(os.Stdout))

名字空间

不支持: 虽然golang标准库是能够正常处理名字空间的,但当前tinydom还无法正确处理xml的名字空间,所有带有名字空间前缀的节点或者属性都会被丢弃。后续计划将这块功能补齐。

BOM

golang的xml解析器自身还不支持BOM,所以本解析器还无法解析带BOM头的xml文件。

Changelog

1.0.0 初始版本
1.1.0 小版本改进,能力增强,bug解决
  • 文档输出增加打印选项控制,支持"优美打印" 接口变更 NewSimplePrinter
  • 优化字符转义切新增转义处理的接口 tinydom.ExcapeText tinydom.ExcapeAttribute
  • 简化接口 Previous 缩写为 Prev,Sibling单词从所有接口中删除
  • 删除接口 InsertAfterChild 建议使用 InsertBack 或者 InsertElementBack 代替
  • 增加接口 Split,InsertFront,InsertBack
  • 增加版本识别函数 tinydom.Version
  • 解决用例稳定性问题
  • 取消支持go-1.4.x版本 因为该版本没有覆盖率统计工具
  • 完善文档
  • github仓库增加了构建服务,文档服务
  • 补充用例,增加代码覆盖率到90%以上
1.2.0 小版本改进,能力增强,bug解决
  • 只是直接指定文件名加载文档或者保存文档:因为这两种场景也比较常见,比较实用
  • 发现1.1.0版本新增函数引入的bug,可能导致对象被切片
  • 将两个全局量PreetyPrint改名为Print在前:因为发现Print在前更容易记忆
  • 完善文档

Documentation

Overview

Package tinydom 实现了一个简单的XML的DOM树构造工具.

Index

Constants

This section is empty.

Variables

View Source
var (
	// PrintPretty  预制的打印选项,采用4个空格缩进
	PrintPretty = PrintOptions{Indent: []byte("    "), TextWrapWidth: 200}

	// PrintStream 流式打印选项,不缩进,不换行,节省流量
	PrintStream = PrintOptions{}
)

Functions

func EscapeAttribute

func EscapeAttribute(w io.Writer, s []byte) error

EscapeAttribute 对XMLElement中的属性值进行转义,常用于自定义文档输出格式

func EscapeText

func EscapeText(w io.Writer, s []byte) error

EscapeText 对文本内容进行转义,常用于自定义文档输出格式

func SaveDocument

func SaveDocument(doc XMLDocument, writer io.Writer, options PrintOptions) error

SaveDocumentToFile Print the xml-dom objects to the writer.

func SaveDocumentToFile

func SaveDocumentToFile(doc XMLDocument, name string, options PrintOptions) error

SaveDocumentToFile Print the xml-dom objects to the file.

func Version

func Version() string

Version 查询版本信息

Types

type DefaultVisitor

type DefaultVisitor struct {
	EnterDocument func(XMLDocument) bool
	ExitDocument  func(XMLDocument) bool
	EnterElement  func(XMLElement) bool
	ExitElement   func(XMLElement) bool
	ProcInst      func(XMLProcInst) bool
	Text          func(XMLText) bool
	Comment       func(XMLComment) bool
	Directive     func(XMLDirective) bool
}

DefaultVisitor 这个类的目的是简化编写定制扫描的visitor,使得我们不需要定制XMLVisitor的所有接口

func (*DefaultVisitor) VisitComment

func (v *DefaultVisitor) VisitComment(c XMLComment) bool

VisitComment is the default implement of XMLVisitor

func (*DefaultVisitor) VisitDirective

func (v *DefaultVisitor) VisitDirective(d XMLDirective) bool

VisitDirective is the default implement of XMLVisitor

func (*DefaultVisitor) VisitEnterDocument

func (v *DefaultVisitor) VisitEnterDocument(doc XMLDocument) bool

VisitEnterDocument is the default implement of XMLVisitor

func (*DefaultVisitor) VisitEnterElement

func (v *DefaultVisitor) VisitEnterElement(elem XMLElement) bool

VisitEnterElement is the default implement of XMLVisitor

func (*DefaultVisitor) VisitExitDocument

func (v *DefaultVisitor) VisitExitDocument(doc XMLDocument) bool

VisitExitDocument is the default implement of XMLVisitor

func (*DefaultVisitor) VisitExitElement

func (v *DefaultVisitor) VisitExitElement(elem XMLElement) bool

VisitExitElement is the default implement of XMLVisitor

func (*DefaultVisitor) VisitProcInst

func (v *DefaultVisitor) VisitProcInst(pi XMLProcInst) bool

VisitProcInst is the default implement of XMLVisitor

func (*DefaultVisitor) VisitText

func (v *DefaultVisitor) VisitText(text XMLText) bool

VisitText is the default implement of XMLVisitor

type PrintOptions

type PrintOptions struct {
	Indent        []byte // 缩进前缀,只允许填写tab或者空白,如果Indent长度为0表示折行但是不缩进,如果Indent为null表示不折行
	TextWrapWidth int    // 超过多长才强制换行
}

PrintOptions 打印选项,用于NewSimplePrinter函数,用于控制输出的XML内容的样式

type XMLAttribute

type XMLAttribute interface {
	Name() string
	Value() string
	SetValue(string)
}

XMLAttribute 是一个元素的属性的接口.

这是一份关于属性的注释.

type XMLComment

type XMLComment interface {
	XMLNode
	Comment() string
	SetComment(string)
}

XMLComment 提供了对注释的封装

func NewComment

func NewComment(comment string) XMLComment

NewComment 创建一个新的XMLComment对象

type XMLDirective

type XMLDirective interface {
	XMLNode
}

XMLDirective 用于表达`<!`与`>`之间的部分,一般为DTD

func NewDirective

func NewDirective(directive string) XMLDirective

NewDirective 创建一个新的XMLDirective对象

type XMLDocument

type XMLDocument interface {
	XMLNode
}

XMLDocument 用于表达一个XML文档,这是整个XML文档的根

func LoadDocument

func LoadDocument(rd io.Reader) (XMLDocument, error)

LoadDocument 从rd流中读取XML码流并构建成XMLDocument对象

func LoadDocumentFromFile

func LoadDocumentFromFile(name string) (XMLDocument, error)

func NewDocument

func NewDocument() XMLDocument

NewDocument 创建一个全新的XMLDocument对象

type XMLElement

type XMLElement interface {
	XMLNode

	Name() string
	SetName(name string)

	FindAttribute(name string) XMLAttribute
	ForeachAttribute(callback func(attribute XMLAttribute) int) int

	AttributeCount() int
	Attribute(name string, def string) string
	SetAttribute(name string, value string) XMLAttribute
	DeleteAttribute(name string) XMLAttribute
	ClearAttributes()

	Text() string
	SetText(text string)
}

XMLElement 提供了访问XML基本节点元素的能力

Name、SetName其实是Value和SetValue的别名,目的是为了使得接口更加符合直观理解。

Text、SetText的作用是设置<node>与</node>之间的文字,虽然文字都是有XMLText对象来承载的,但是通常来说直接在XMLElement中访问会更加方便。

FindAttribute和ForeachAttribute分别用于查找特定的XML节点的属性和遍历XML属性列表。

Attribute、SetAttribute、DeleteAttribute用于读取和删除属性。

func NewElement

func NewElement(name string) XMLElement

NewElement 创建一个新的XMLElement对象

type XMLHandle

type XMLHandle interface {
	Parent() XMLHandle
	FirstChild() XMLHandle
	LastChild() XMLHandle
	Prev() XMLHandle
	Next() XMLHandle
	FirstChildElement(name string) XMLHandle
	LastChildElement(name string) XMLHandle
	PrevElement(name string) XMLHandle
	NextElement(name string) XMLHandle

	ToNode() XMLNode
	ToElement() XMLElement
	ToText() XMLText
	ToComment() XMLComment
	ToDocument() XMLDocument
	ToProcInst() XMLProcInst
	ToDirective() XMLDirective
}

XMLHandle XML文档处理器,其主要

func NewHandle

func NewHandle(node XMLNode) XMLHandle

NewHandle 创建一个新的XMLHandle对象

type XMLNode

type XMLNode interface {
	ToElement() XMLElement
	ToText() XMLText
	ToComment() XMLComment
	ToDocument() XMLDocument
	ToProcInst() XMLProcInst
	ToDirective() XMLDirective

	Value() string
	SetValue(newValue string)

	Document() XMLDocument

	NoChildren() bool
	Parent() XMLNode
	FirstChild() XMLNode
	LastChild() XMLNode
	Prev() XMLNode
	Next() XMLNode
	FirstChildElement(name string) XMLElement
	LastChildElement(name string) XMLElement
	PrevElement(name string) XMLElement
	NextElement(name string) XMLElement

	InsertBack(node XMLNode) XMLNode
	InsertFront(node XMLNode) XMLNode
	InsertEndChild(node XMLNode) XMLNode
	InsertFirstChild(node XMLNode) XMLNode

	InsertElementBack(name string) XMLElement
	InsertElementFront(name string) XMLElement
	InsertElementEndChild(name string) XMLElement
	InsertElementFirstChild(name string) XMLElement

	DeleteChildren()
	DeleteChild(node XMLNode)

	Split() XMLNode

	Accept(visitor XMLVisitor) bool
	// contains filtered or unexported methods
}

XMLNode 定义了XML所有节点的基础设施,提供了基本的元素遍历、增删等操作,也提供了逆向转换能力.

type XMLProcInst

type XMLProcInst interface {
	XMLNode
	Target() string
	Instruction() string
}

XMLProcInst 常用于表达XML处理指令,类似:<?xml version="1.0" encoding="UTF-8"?>

func NewProcInst

func NewProcInst(target string, inst string) XMLProcInst

NewProcInst 创建一个新的XMLProcInst对象

type XMLText

type XMLText interface {
	XMLNode
	SetCDATA(isCData bool)
	CDATA() bool
}

XMLText 提供了对XML元素间文本的封装

func NewText

func NewText(text string) XMLText

NewText 创建一个新的XMLText对象

type XMLVisitor

type XMLVisitor interface {
	VisitEnterDocument(XMLDocument) bool
	VisitExitDocument(XMLDocument) bool

	VisitEnterElement(XMLElement) bool
	VisitExitElement(XMLElement) bool

	VisitProcInst(XMLProcInst) bool
	VisitText(XMLText) bool
	VisitComment(XMLComment) bool
	VisitDirective(XMLDirective) bool
}

XMLVisitor XML文档访问器,常用于遍历文档或者格式化输出XML文档

func NewSimplePrinter

func NewSimplePrinter(writer io.Writer, options PrintOptions) XMLVisitor

NewSimplePrinter 创建一个简单XML文档输出函数

Jump to

Keyboard shortcuts

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