github.com/gogf/gf/v2@v2.7.4/encoding/gxml/gxml.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 // Package gxml provides accessing and converting for XML content. 8 package gxml 9 10 import ( 11 "strings" 12 13 "github.com/clbanning/mxj/v2" 14 15 "github.com/gogf/gf/v2/encoding/gcharset" 16 "github.com/gogf/gf/v2/errors/gerror" 17 "github.com/gogf/gf/v2/text/gregex" 18 ) 19 20 // Decode parses `content` into and returns as map. 21 func Decode(content []byte) (map[string]interface{}, error) { 22 res, err := convert(content) 23 if err != nil { 24 return nil, err 25 } 26 m, err := mxj.NewMapXml(res) 27 if err != nil { 28 err = gerror.Wrapf(err, `mxj.NewMapXml failed`) 29 } 30 return m, err 31 } 32 33 // DecodeWithoutRoot parses `content` into a map, and returns the map without root level. 34 func DecodeWithoutRoot(content []byte) (map[string]interface{}, error) { 35 res, err := convert(content) 36 if err != nil { 37 return nil, err 38 } 39 m, err := mxj.NewMapXml(res) 40 if err != nil { 41 err = gerror.Wrapf(err, `mxj.NewMapXml failed`) 42 return nil, err 43 } 44 for _, v := range m { 45 if r, ok := v.(map[string]interface{}); ok { 46 return r, nil 47 } 48 } 49 return m, nil 50 } 51 52 // XMLEscapeChars forces escaping invalid characters in attribute and element values. 53 // NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is 54 // then '&' will be re-escaped as '&amp;'. 55 // 56 /* 57 The values are: 58 " " 59 ' ' 60 < < 61 > > 62 & & 63 */ 64 // 65 // Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value 66 // has been toggled to 'true' - then XMLEscapeChars(true) is ignored. If XMLEscapeChars(true) 67 // has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called 68 // to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'. 69 func XMLEscapeChars(b ...bool) { 70 mxj.XMLEscapeChars(b...) 71 } 72 73 // Encode encodes map `m` to an XML format content as bytes. 74 // The optional parameter `rootTag` is used to specify the XML root tag. 75 func Encode(m map[string]interface{}, rootTag ...string) ([]byte, error) { 76 b, err := mxj.Map(m).Xml(rootTag...) 77 if err != nil { 78 err = gerror.Wrapf(err, `mxj.Map.Xml failed`) 79 } 80 return b, err 81 } 82 83 // EncodeWithIndent encodes map `m` to an XML format content as bytes with indent. 84 // The optional parameter `rootTag` is used to specify the XML root tag. 85 func EncodeWithIndent(m map[string]interface{}, rootTag ...string) ([]byte, error) { 86 b, err := mxj.Map(m).XmlIndent("", "\t", rootTag...) 87 if err != nil { 88 err = gerror.Wrapf(err, `mxj.Map.XmlIndent failed`) 89 } 90 return b, err 91 } 92 93 // ToJson converts `content` as XML format into JSON format bytes. 94 func ToJson(content []byte) ([]byte, error) { 95 res, err := convert(content) 96 if err != nil { 97 return nil, err 98 } 99 mv, err := mxj.NewMapXml(res) 100 if err == nil { 101 return mv.Json() 102 } 103 err = gerror.Wrap(err, `mxj.NewMapXml failed`) 104 return nil, err 105 } 106 107 // convert does convert the encoding of given XML content from XML root tag into UTF-8 encoding content. 108 func convert(xml []byte) (res []byte, err error) { 109 var ( 110 patten = `<\?xml.*encoding\s*=\s*['|"](.*?)['|"].*\?>` 111 matchStr, _ = gregex.MatchString(patten, string(xml)) 112 xmlEncode = "UTF-8" 113 ) 114 if len(matchStr) == 2 { 115 xmlEncode = matchStr[1] 116 } 117 xmlEncode = strings.ToUpper(xmlEncode) 118 res, err = gregex.Replace(patten, []byte(""), xml) 119 if err != nil { 120 return nil, err 121 } 122 if xmlEncode != "UTF-8" && xmlEncode != "UTF8" { 123 dst, err := gcharset.Convert("UTF-8", xmlEncode, string(res)) 124 if err != nil { 125 return nil, err 126 } 127 res = []byte(dst) 128 } 129 return res, nil 130 }