| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package base
- import (
- "bytes"
- "crypto/md5"
- "encoding/hex"
- "encoding/xml"
- "errors"
- "hash"
- "io"
- "sort"
- "sync"
- )
- var textBufferPool = sync.Pool{
- New: func() interface{} {
- return bytes.NewBuffer(make([]byte, 0, 16<<10)) // 16KB
- },
- }
- // FormatMapToXML marshal map[string]string to xmlWriter with xml format, the root node name is xml.
- // NOTE: This function assumes the key of m map[string]string are legitimate xml name string
- // that does not contain the required escape character!
- func FormatMapToXML(xmlWriter io.Writer, m map[string]string) (err error) {
- if xmlWriter == nil {
- return errors.New("nil xmlWriter")
- }
- if _, err = io.WriteString(xmlWriter, "<xml>"); err != nil {
- return
- }
- for k, v := range m {
- if _, err = io.WriteString(xmlWriter, "<"+k+">"); err != nil {
- return
- }
- if err = xml.EscapeText(xmlWriter, []byte(v)); err != nil {
- return
- }
- if _, err = io.WriteString(xmlWriter, "</"+k+">"); err != nil {
- return
- }
- }
- if _, err = io.WriteString(xmlWriter, "</xml>"); err != nil {
- return
- }
- return
- }
- // 微信支付签名.
- // parameters: 待签名的参数集合
- // apiKey: API密钥
- // fn: func() hash.Hash, 如果 fn == nil 则默认用 md5.New
- func Sign(parameters map[string]string, apiKey string, fn func() hash.Hash) string {
- ks := make([]string, 0, len(parameters))
- for k := range parameters {
- if k == "sign" {
- continue
- }
- ks = append(ks, k)
- }
- sort.Strings(ks)
- if fn == nil {
- fn = md5.New
- }
- h := fn()
- buf := make([]byte, 256)
- for _, k := range ks {
- v := parameters[k]
- if v == "" {
- continue
- }
- buf = buf[:0]
- buf = append(buf, k...)
- buf = append(buf, '=')
- buf = append(buf, v...)
- buf = append(buf, '&')
- h.Write(buf)
- }
- buf = buf[:0]
- buf = append(buf, "key="...)
- buf = append(buf, apiKey...)
- h.Write(buf)
- signature := make([]byte, h.Size()*2)
- hex.Encode(signature, h.Sum(nil))
- return string(bytes.ToUpper(signature))
- }
- // ParseXMLToMap parses xml reading from xmlReader and returns the first-level sub-node key-value set,
- // if the first-level sub-node contains child nodes, skip it.
- func ParseXMLToMap(xmlReader io.Reader) (m map[string]string, err error) {
- if xmlReader == nil {
- err = errors.New("nil xmlReader")
- return
- }
- m = make(map[string]string)
- var (
- d = xml.NewDecoder(xmlReader)
- tk xml.Token
- depth = 0 // current xml.Token depth
- key string
- value bytes.Buffer
- )
- for {
- tk, err = d.Token()
- if err != nil {
- if err == io.EOF {
- err = nil
- }
- return
- }
- switch v := tk.(type) {
- case xml.StartElement:
- depth++
- switch depth {
- case 2:
- key = v.Name.Local
- value.Reset()
- case 3:
- if err = d.Skip(); err != nil {
- return
- }
- depth--
- key = "" // key == "" indicates that the node with depth==2 has children
- }
- case xml.CharData:
- if depth == 2 && key != "" {
- value.Write(v)
- }
- case xml.EndElement:
- if depth == 2 && key != "" {
- m[key] = value.String()
- }
- depth--
- }
- }
- }
|