关于Etree XML官方文档
etree
The etree package is a lightweight, pure go package that expresses XML in the form of an element tree. Its design was inspired by the Python ElementTree module.
Some of the package's capabilities and features:
Represents XML documents as trees of elements for easy traversal.
Imports, serializes, modifies or creates XML documents from scratch.
Writes and reads XML to/from files, byte slices, strings and io interfaces.
Performs simple or complex searches with lightweight XPath-like query APIs.
Auto-indents XML using spaces or tabs for better readability.
Implemented in pure go; depends only on standard go libraries.
Built on top of the go encoding/xml package.
范例1:创建一个XML文档
package main
import (
"os"
etree "github.com/beevik/etree"
)
func main() {
doc := etree.NewDocument()
doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
doc.CreateProcInst("xml-stylesheet", `type="text/xsl" href="style.xsl"`)
people := doc.CreateElement("People")
people.CreateComment("These are all known people")
jon := people.CreateElement("Person")
jon.CreateAttr("name", "Jon")
sally := people.CreateElement("Person")
sally.CreateAttr("name", "Sally")
doc.Indent(2)
doc.WriteTo(os.Stdout)
}
输出:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="style.xsl"?> <People> <!--These are all known people--> <Person name="Jon"/> <Person name="Sally"/> </People>
eading an XML file
Suppose you have a file on disk called bookstore.xml containing the following data:
<bookstore xmlns:p="urn:schemas-books-com:prices">
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<p:price>30.00</p:price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<p:price>29.99</p:price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<p:price>49.99</p:price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<p:price>39.95</p:price>
</book>
</bookstore>
This code reads the file's contents into an etree document.
doc := etree.NewDocument()
if err := doc.ReadFromFile("bookstore.xml"); err != nil {
panic(err)
}
You can also read XML from a string, a byte slice, or an io.Reader.
Processing elements and attributes
This example illustrates several ways to access elements and attributes using etree selection queries.
root := doc.SelectElement("bookstore")
fmt.Println("ROOT element:", root.Tag)
for _, book := range root.SelectElements("book") {
fmt.Println("CHILD element:", book.Tag)
if title := book.SelectElement("title"); title != nil {
lang := title.SelectAttrValue("lang", "unknown")
fmt.Printf(" TITLE: %s (%s)
", title.Text(), lang)
}
for _, attr := range book.Attr {
fmt.Printf(" ATTR: %s=%s
", attr.Key, attr.Value)
}
}
完整实例:
package main
import (
"fmt"
etree "github.com/beevik/etree"
)
func main() {
doc := etree.NewDocument()
if err := doc.ReadFromFile("bookstore.xml"); err != nil {
panic(err)
}
root := doc.SelectElement("bookstore")
fmt.Println("ROOT element:", root.Tag)
for _, book := range root.SelectElements("book") {
fmt.Println("CHILD element:", book.Tag)
if title := book.SelectElement("title"); title != nil {
lang := title.SelectAttrValue("lang", "unknown")
fmt.Printf(" TITLE: %s (%s)
", title.Text(), lang)
}
for _, attr := range book.Attr {
fmt.Printf(" ATTR: %s=%s
", attr.Key, attr.Value)
}
}
}
输出:
ROOT element: bookstore
CHILD element: book
TITLE: Everyday Italian (en)
ATTR: category=COOKING
CHILD element: book
TITLE: Harry Potter (en)
ATTR: category=CHILDREN
CHILD element: book
TITLE: XQuery Kick Start (en)
ATTR: category=WEB
CHILD element: book
TITLE: Learning XML (en)
ATTR: category=WEB
Path queries
This example uses etree's path functions to select all book titles that fall into the category of 'WEB'. The double-slash prefix in the path causes the search for book elements to occur recursively; book elements may appear at any level of the XML hierarchy.
for _, t := range doc.FindElements("//book[@category='WEB']/title") {
fmt.Println("Title:", t.Text())
}
Output:
Title: XQuery Kick Start Title: Learning XML
This example finds the first book element under the root bookstore element and outputs the tag and text of each of its child elements.
for _, e := range doc.FindElements("./bookstore/book[1]/*") {
fmt.Printf("%s: %s
", e.Tag, e.Text())
}
Output:
title: Everyday Italian author: Giada De Laurentiis year: 2005 price: 30.00
This example finds all books with a price of 49.99 and outputs their titles.
path := etree.MustCompilePath("./bookstore/book[p:price='49.99']/title")
for _, e := range doc.FindElementsPath(path) {
fmt.Println(e.Text())
}
Output:
XQuery Kick Start
Note that this example uses the FindElementsPath function, which takes as an argument a pre-compiled path object. Use precompiled paths when you plan to search with the same path more than once.
Other features
These are just a few examples of the things the etree package can do. See the documentation for a complete description of its capabilities.
Contributing
This project accepts contributions. Just fork the repo and submit a pull request!
etree作为一个轮子在解析XML文件的工具中占据着很重要的地位,它可以查找节点,轮询、生成XML文件。
一、XML的引入写法
在工程中引入XML的方法,建议用第一种
//方法一
xml := ` <bookstore> <book> <title>Great Expectations</title> <author>Charles Dickens</author> </book> <book> <title>Ulysses</title> <author>James Joyce</author> </book> </bookstore>`
//方法二
LoginPut= "<?xml version="1.0" encoding="UTF-8" standalone="yes"?>" + " <LogonRequest xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/"" + " schemaVersion="V1_1_0">" + " <Metadata>" + " <Atom/>" + " </Metadata>" + " <UserID >%s</UserID>" + " <Password >%s</Password>" + " </LogonRequest>"
二、XML的解析
1. 判断所需节点是否存在的方法
方法1:在某个节点范围下查找指定节点是否存在
//whetherExistNode 判断节点是否存在
func whetherExistNode(doc etree.Element, nodeName string) (exist bool) {
path := etree.MustCompilePath(nodeName)
bb := doc.FindElementPath(path)
if bb != nil {
return true
} else {
return false
}
return exist
}
方法2:获取指定节点的值
//getSpecifiedNodeVal 获取指定节点的值
func getSpecifiedNodeVal(doc etree.Document, nodeName string) (dataSlice []string) {
path := etree.MustCompilePath(nodeName)
var val string
for _, t := range doc.FindElementsPath(path) {
val = t.Text()
if len(dataSlice) <= 0 {
dataSlice = append(dataSlice, val)
} else {
repeat := false
for i := 0; i < len(dataSlice); i++ {
if dataSlice[i] == val {
repeat = true
}
}
if !repeat {
dataSlice = append(dataSlice, val)
}
}
}
return dataSlice
}
方法3:在用SelectElement获取节点值的时候 要判断改节点是否存在,如果不加判断,程序直接就会panic退出,后果会比较严重。
if tempNode.SelectElement("OperatingSystemVersion") != nil {
systemVersion = tempNode.SelectElement("OperatingSystemVersion").Text()
if systemVersion != "" {
systemType = util.GetOSType(systemVersion)
}
} else {
systemVersion = ""
}
注意点:在用FindElementsPath或FindElements查找节点时建议用FindElementsPath,因为FindElements在查找不到节点时会panic报错,SelectElement和SelectElements,的用法,SelectElements获取到的结果为数组,SelectElement标识选中的单一的节点。
path := etree.MustCompilePath("//PartitionName")
doc.FindElementsPath(path)
重点:1.在获取节点值的时候一定要判断节点是否为空
2.添加//标识从头开始查找值
3.doc.SelectElement必须选中开始的父节点,不能跨区域
//FindElementPath 指定父节点查找指定的接点值:节点不存在不会报错
aa := doc.SelectElement("feed").SelectElement("entry")
path := etree.MustCompilePath("updatedd")
cc := aa.FindElementPath(path)
if cc != nil {
fmt.Println(cc.Text())
} else {
fmt.Println("cc == nil")
}
2.etree支持接口返回内容和XML文件两种解析方式
测试用的data.xml文件
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
<id>5134c4aa-8df4-3d41-aafc-927a7546f8b8</id>
<updated>2019-09-25T03:03:29.615Z</updated>
<link rel="SELF" href="https://192.168.10.51:12443/rest/api/uom/ManagedSystem/c13e47ce-5967-3845-a500-4b8947a9fb10/LogicalPartition"/>
<link rel="MANAGEMENT_CONSOLE" href="https://192.168.10.51:12443/rest/api/uom/ManagementConsole/525cb072-1d11-3969-9245-053f0ac6f406"/>
<generator>IBM Power Systems Management Console</generator>
<entry>
<id>323F5D6D-E501-4166-9522-B216B1565862</id>
<title>LogicalPartition</title>
<published>2019-09-25T03:03:29.914Z</published>
<link rel="SELF" href="https://192.168.10.51:12443/rest/api/uom/ManagedSystem/c13e47ce-5967-3845-a500-4b8947a9fb10/LogicalPartition/323F5D6D-E501-4166-9522-B216B1565862"/>
<author>
<name>IBM Power Systems Management Console</name>
</author>
<etag:etag xmlns:etag="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/">-170243083</etag:etag>
</entry>
<entry>
<id>21FE0160-FF83-4852-909B-B7D264E258C8</id>
<title>LogicalPartition</title>
<published>2019-09-25T03:03:29.916Z</published>
<link rel="SELF" href="https://192.168.10.51:12443/rest/api/uom/ManagedSystem/c13e47ce-5967-3845-a500-4b8947a9fb10/LogicalPartition/21FE0160-FF83-4852-909B-B7D264E258C8"/>
<author>
<name>IBM Power Systems Management Console</name>
</author>
<etag:etag xmlns:etag="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/">-1052118977</etag:etag>
</entry>
</feed>
var testData string = `<entry>
<id>21FE0160-FF83-4852-909B-B7D264E258C8</id>
<title>LogicalPartition</title>
<published>2019-09-25T03:03:29.916Z</published>
<link rel="SELF" href="https://192.168.10.51:12443/rest/api/uom/ManagedSystem/c13e47ce-5967-3845-a500-4b8947a9fb10/LogicalPartition/21FE0160-FF83-4852-909B-B7D264E258C8"/>
<author>
<name>IBM Power Systems Management Console</name>
</author>
<etag:etag xmlns:etag="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/">-1052118977</etag:etag>
</entry>`
package main
import (
"fmt"
etree "github.com/beevik/etree"
)
var testData string = `<entry>
<id>21FE0160-FF83-4852-909B-B7D264E258C8</id>
<title>LogicalPartition</title>
<published>2019-09-25T03:03:29.916Z</published>
<link rel="SELF" href="https://192.168.10.51:12443/rest/api/uom/ManagedSystem/c13e47ce-5967-3845-a500-4b8947a9fb10/LogicalPartition/21FE0160-FF83-4852-909B-B7D264E258C8"/>
<author>
<name>IBM Power Systems Management Console</name>
</author>
<etag:etag xmlns:etag="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/">-1052118977</etag:etag>
</entry>`
func main() {
//读取字符串的方法-----------采用绝对路径的方法
doc := etree.NewDocument()
if err := doc.ReadFromString(testData); err != nil {
panic(err)
}
res := doc.FindElement("./entry[0]/id").Text()
fmt.Println(res)
// doc := etree.NewDocument()
// if err := doc.ReadFromFile("data.xml"); err != nil {
// panic(err)
// }
// servers := doc.SelectElement("feed")
// for _, server := range servers.SelectElements("entry") {
// if server.SelectElement("author").SelectElement("name") == nil {
// fmt.Println("测试节点不存在")
// } else {
// fmt.Println(server.SelectElement("author").SelectElement("name").Text())
// }
// }
}
输出:
21FE0160-FF83-4852-909B-B7D264E258C8
package main
import (
"fmt"
etree "github.com/beevik/etree"
)
func main() {
doc := etree.NewDocument()
if err := doc.ReadFromFile("data.xml"); err != nil {
panic(err)
}
servers := doc.SelectElement("feed")
for _, server := range servers.SelectElements("entry") {
if server.SelectElement("author").SelectElement("name") == nil {
fmt.Println("测试节点不存在")
} else {
fmt.Println(server.SelectElement("author").SelectElement("name").Text())
}
}
}
输出:
IBM Power Systems Management Console
IBM Power Systems Management Console