golang学习笔记 ---etree包

关于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)\n", title.Text(), lang)
    }
    for _, attr := range book.Attr {
        fmt.Printf("  ATTR: %s=%s\n", 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)\n", title.Text(), lang)
		}
		for _, attr := range book.Attr {
			fmt.Printf("  ATTR: %s=%s\n", 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\n", 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

 

posted on 2021-10-09 11:46  清明-心若淡定  阅读(1917)  评论(0编辑  收藏  举报