gf架構之gparser - 強大靈活的資料格式編碼/解析包
來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。gf架構針對常用的資料格式編碼解析,提供了異常強大靈活的功能,由gparser包提供,**支援Go變數(interface{})、Struct、JSON、XML、YAML/YML、TOML資料格式之間的相互轉換**,支援按照層級進行資料檢索訪問、支援運行時動態新增/修改/刪除層級變數(並發安全)等特性。gparser包使得對於未知資料結構、多維陣列結構的訪問、操作變得異常的簡便。使用方式:```goimport "gitee.com/johng/gf/g/encoding/gparser"```### 方法列表```gofunc VarToJson(value interface{}) ([]byte, error)func VarToJsonIndent(value interface{}) ([]byte, error)func VarToToml(value interface{}) ([]byte, error)func VarToXml(value interface{}, rootTag ...string) ([]byte, error)func VarToXmlIndent(value interface{}, rootTag ...string) ([]byte, error)func VarToYaml(value interface{}) ([]byte, error)func VarToStruct(value interface{}, obj interface{}) errortype Parser func Load(path string) (*Parser, error) func LoadContent(data []byte, fileType string) (*Parser, error) func New(values ...interface{}) *Parser func (p *Parser) Get(pattern string) interface{} func (p *Parser) GetArray(pattern string) []interface{} func (p *Parser) GetBool(pattern string) bool func (p *Parser) GetFloat32(pattern string) float32 func (p *Parser) GetFloat64(pattern string) float64 func (p *Parser) GetInt(pattern string) int func (p *Parser) GetMap(pattern string) map[string]interface{} func (p *Parser) GetString(pattern string) string func (p *Parser) GetToVar(pattern string, v interface{}) error func (p *Parser) GetUint(pattern string) uint func (p *Parser) Remove(pattern string) error func (p *Parser) Set(pattern string, value interface{}) error func (p *Parser) ToArray() []interface{} func (p *Parser) ToJson() ([]byte, error) func (p *Parser) ToJsonIndent() ([]byte, error) func (p *Parser) ToMap() map[string]interface{} func (p *Parser) ToToml() ([]byte, error) func (p *Parser) ToXml(rootTag ...string) ([]byte, error) func (p *Parser) ToXmlIndent(rootTag ...string) ([]byte, error) func (p *Parser) ToYaml() ([]byte, error) func (p *Parser) ToStruct(v interface{}) error```方法簡要說明,1. Load與LoadContent方法支援根據檔案及內容,產生gparser.Parser對象;2. New方法支援產生一個空的gparser.Parser對象,常用用於動態資料產生;3. New方法同時也支援按照給定的任意Go變數產生一個gparser.Parser對象;3. Get\*相關方法支援按照層級檢索資料,pattern參數中使用英文"."號區分層級關係;4. Set方法支援按照層級新增/修改,給定的**變數類型支援任意類型**;5. Remove方法支援按照層級刪除變數,只需要給定pattern層級檢索參數即可;5. To\*相關方法支援將gparser.Parser對象產生為支援的資料格式字串;6. VarTo\*相關方法支援將**任意的Go變數**直接轉換為支援的資料格式字串;### 使用樣本1. **資料層級檢索**樣本1,讀取JSON: ```go data := `{ "users" : { "count" : 100, "list" : [ {"name" : "Ming", "score" : 60}, {"name" : "John", "score" : 99.5} ] } }` if p, e := gparser.LoadContent([]byte(data), "json"); e != nil { glog.Error(e) } else { fmt.Println("John Score:", p.GetFloat32("users.list.1.score")) } ``` 可以看到我們可以通過英文"."號實現非常方便的層級訪問,針對於數組列表,索引從0開始,我們也可以通過"."號訪問其對應的索引項目資料。 樣本2,讀取XML: ```go data := `<?xml version="1.0" encoding="UTF-8"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>` if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil { glog.Error(e) } else { fmt.Println("Heading:", p.GetString("note.heading")) } ``` LoadContent方法的第二個參數指定內容的資料類型,可選值為(json,xml,yaml/yml,toml)。其他兩種資料類型可自行測試,這裡不再贅述。 2. **處理鍵名本身帶有層級符號"."的情況**當鍵名和層級在訪問時存在pattern同名的情況,當然這並不是什麼問題,以下是一個樣本。 ```go data := `{ "users" : { "count" : 100 }, "users.count" : 101 }` if p, e := gparser.LoadContent([]byte(data), "json"); e != nil { glog.Error(e) } else { fmt.Println("Users Count:", p.Get("users.count")) } ``` 運行之後列印出的結果為```101```。當鍵名存在"."號時,檢索優先順序:鍵名->層級,因此並不會引起歧義。 再來看一個例子: ```go data := `{ "users" : { "count" : { "type1" : 1, "type2" : 2 }, "count.type1" : 100 } }` if p, e := gparser.LoadContent([]byte(data), "json"); e != nil { glog.Error(e) } else { fmt.Println("Users Count:", p.Get("users.count.type1")) fmt.Println("Users Count:", p.Get("users.count.type2")) } ``` 執行後,輸出結果為: ``` 100 2 ``` 看到了麼,gparser會按照給定pattern對層級進行自動探測,檢索時按照鍵名優先的原則進行匹配,並不會出現歧義衝突。 3. **運行時動態修改資料** ```go data := `{ "users" : { "count" : 100 } }` if p, e := gparser.LoadContent([]byte(data), "json"); e != nil { glog.Error(e) } else { p.Set("users.count", 2) p.Set("users.list", []string{"John", "小明"}) c, _ := p.ToJson() fmt.Println(string(c)) } ``` 修改count為2,並在users節點下新增增加list節點,節點類型為數組。 執行後輸出結果為: ```json {"users":{"count":2,"list":["John","小明"]}} ```gparser包的資料運行時修改特性非常強大,在該特性的支援下,各種資料結構的編碼/解析顯得異常的靈活方便。 4. **運行時動態刪除變數** 我們再來看一個刪除變數的例子: ```go data := `<?xml version="1.0" encoding="UTF-8"?> <article> <count>10</count> <list><title>gf article1</title><content>gf content1</content></list> <list><title>gf article2</title><content>gf content2</content></list> <list><title>gf article3</title><content>gf content3</content></list> </article>` if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil { glog.Error(e) } else { p.Remove("article.list.0") c, _ := p.ToJson() fmt.Println(string(c)) } ```以上程式輸出結果為: ```json{"article":{"count":"10","list":[{"content":"gf content2","title":"gf article2"},{"content":"gf content3","title":"gf article3"}]}} ``` 可以看到,使用Remove方法可以非常方便地根據pattern參數動態刪除變數。在該樣本中,我們刪除了article.list數組的索引0資料項目,並將XML轉換為JSON資料格式返回。 5. **動態產生指定格式的編碼資料**我們來動態產生一個XML,先來一個簡單一點的。 ```go p := gparser.New() p.Set("name", "john") p.Set("age", 18) p.Set("scores", map[string]int{ "語文" : 100, "數學" : 100, "英語" : 100, }) c, _ := p.ToXmlIndent("simple-xml") fmt.Println(string(c)) ``` 執行後,輸出結果為: ```xml <simple-xml> <age>18</age> <name>john</name> <scores> <數學>100</數學> <英語>100</英語> <語文>100</語文> </scores> </simple-xml> ```可以看到,我們直接使用Set方式便建立了一個XML資料格式,根本就不需要struct有木有?!想要struct?當然也可以,請看下面的樣本。 6. **變數與struct相互轉換**樣本1,struct轉換為gparser.Parser對象,並轉換輸出為JSON格式: ```go type Order struct { Id int `json:"id"` Price float32 `json:"price"` } p := gparser.New() p.Set("orders.list.0", Order{1, 100}) p.Set("orders.list.1", Order{2, 666}) p.Set("orders.list.2", Order{3, 999.99}) fmt.Println("Order 1 Price:", p.Get("orders.list.1.price")) c, _ := p.ToJson() fmt.Println(string(c)) ``` 執行後,輸出結果為: ``` Order 1 Price: 666 {"orders":{"list":{"0":{"id":1,"price":100},"1":{"id":2,"price":666},"2":{"id":3,"price":999.99}}}} ``` 怎麼樣,有沒有覺得很6? 但是針對於struct處理,這裡有一點需要特別說明的是,如果struct中的變數不對外公開,那麼該變數同時也不能被gparser通過層級檢索方式訪問到。由於gparser的底層資料結構採用了json格式,如果struct同時定義了json tag,那麼層級檢索將會按照json tag進行檢索訪問,不支援struct的其他tag類型。 樣本2,變數轉換為struct對象: ```go type Info struct { Name string Url string } o := Info{} p := gparser.New(map[string]string{ "Name" : "gf", "Url" : "https://gitee.com/johng", }) p.ToStruct(&o) fmt.Println("Name:", o.Name) fmt.Println("Url :", o.Url) ``` 執行後,輸出為: ``` Name: gf Url : https://gitee.com/johng ``` 當然,也可以直接使用gparser.VarToStruct方法來進行直接轉換。7. **資料格式相互轉換**由於只是示範資料格式的轉換,咱們來個資料結構簡單點的: ```go p := gparser.New(map[string]string{ "name" : "gf", "site" : "https://gitee.com/johng", }) c, _ := p.ToJson() fmt.Println("JSON:") fmt.Println(string(c)) fmt.Println("======================") fmt.Println("XML:") c, _ = p.ToXmlIndent() fmt.Println(string(c)) fmt.Println("======================") fmt.Println("YAML:") c, _ = p.ToYaml() fmt.Println(string(c)) fmt.Println("======================") fmt.Println("TOML:") c, _ = p.ToToml() fmt.Println(string(c)) ``` 執行後,輸出結果為: ``` JSON: {"name":"gf","site":"https://gitee.com/johng"} ====================== XML: <doc> <name>gf</name> <site>https://gitee.com/johng</site> </doc> ====================== YAML: name: gf site: https://gitee.com/johng ====================== TOML: name = "gf" site = "https://gitee.com/johng" ``` 可以看到,gparser包使得資料格式的轉換變得異常的方便靈活。 239 次點擊