tools.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package base
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "encoding/xml"
  7. "errors"
  8. "hash"
  9. "io"
  10. "sort"
  11. "sync"
  12. )
  13. var textBufferPool = sync.Pool{
  14. New: func() interface{} {
  15. return bytes.NewBuffer(make([]byte, 0, 16<<10)) // 16KB
  16. },
  17. }
  18. // FormatMapToXML marshal map[string]string to xmlWriter with xml format, the root node name is xml.
  19. // NOTE: This function assumes the key of m map[string]string are legitimate xml name string
  20. // that does not contain the required escape character!
  21. func FormatMapToXML(xmlWriter io.Writer, m map[string]string) (err error) {
  22. if xmlWriter == nil {
  23. return errors.New("nil xmlWriter")
  24. }
  25. if _, err = io.WriteString(xmlWriter, "<xml>"); err != nil {
  26. return
  27. }
  28. for k, v := range m {
  29. if _, err = io.WriteString(xmlWriter, "<"+k+">"); err != nil {
  30. return
  31. }
  32. if err = xml.EscapeText(xmlWriter, []byte(v)); err != nil {
  33. return
  34. }
  35. if _, err = io.WriteString(xmlWriter, "</"+k+">"); err != nil {
  36. return
  37. }
  38. }
  39. if _, err = io.WriteString(xmlWriter, "</xml>"); err != nil {
  40. return
  41. }
  42. return
  43. }
  44. //Sign 微信支付签名.
  45. // parameters: 待签名的参数集合
  46. // apiKey: API密钥
  47. // fn: func() hash.Hash, 如果 fn == nil 则默认用 md5.New
  48. func Sign(parameters map[string]string, apiKey string, fn func() hash.Hash) string {
  49. ks := make([]string, 0, len(parameters))
  50. for k := range parameters {
  51. if k == "sign" {
  52. continue
  53. }
  54. ks = append(ks, k)
  55. }
  56. sort.Strings(ks)
  57. if fn == nil {
  58. fn = md5.New
  59. }
  60. h := fn()
  61. buf := make([]byte, 256)
  62. for _, k := range ks {
  63. v := parameters[k]
  64. if v == "" {
  65. continue
  66. }
  67. buf = buf[:0]
  68. buf = append(buf, k...)
  69. buf = append(buf, '=')
  70. buf = append(buf, v...)
  71. buf = append(buf, '&')
  72. h.Write(buf)
  73. }
  74. buf = buf[:0]
  75. buf = append(buf, "key="...)
  76. buf = append(buf, apiKey...)
  77. h.Write(buf)
  78. signature := make([]byte, h.Size()*2)
  79. hex.Encode(signature, h.Sum(nil))
  80. return string(bytes.ToUpper(signature))
  81. }
  82. // ParseXMLToMap parses xml reading from xmlReader and returns the first-level sub-node key-value set,
  83. // if the first-level sub-node contains child nodes, skip it.
  84. func ParseXMLToMap(xmlReader io.Reader) (m map[string]string, err error) {
  85. if xmlReader == nil {
  86. err = errors.New("nil xmlReader")
  87. return
  88. }
  89. m = make(map[string]string)
  90. var (
  91. d = xml.NewDecoder(xmlReader)
  92. tk xml.Token
  93. depth = 0 // current xml.Token depth
  94. key string
  95. value bytes.Buffer
  96. )
  97. for {
  98. tk, err = d.Token()
  99. if err != nil {
  100. if err == io.EOF {
  101. err = nil
  102. }
  103. return
  104. }
  105. switch v := tk.(type) {
  106. case xml.StartElement:
  107. depth++
  108. switch depth {
  109. case 2:
  110. key = v.Name.Local
  111. value.Reset()
  112. case 3:
  113. if err = d.Skip(); err != nil {
  114. return
  115. }
  116. depth--
  117. key = "" // key == "" indicates that the node with depth==2 has children
  118. }
  119. case xml.CharData:
  120. if depth == 2 && key != "" {
  121. value.Write(v)
  122. }
  123. case xml.EndElement:
  124. if depth == 2 && key != "" {
  125. m[key] = value.String()
  126. }
  127. depth--
  128. }
  129. }
  130. }