anyxml.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package mxj
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "reflect"
  6. )
  7. const (
  8. DefaultElementTag = "element"
  9. )
  10. // Encode arbitrary value as XML.
  11. //
  12. // Note: unmarshaling the resultant
  13. // XML may not return the original value, since tag labels may have been injected
  14. // to create the XML representation of the value.
  15. /*
  16. Encode an arbitrary JSON object.
  17. package main
  18. import (
  19. "encoding/json"
  20. "fmt"
  21. "github.com/clbanning/mxj"
  22. )
  23. func main() {
  24. jsondata := []byte(`[
  25. { "somekey":"somevalue" },
  26. "string",
  27. 3.14159265,
  28. true
  29. ]`)
  30. var i interface{}
  31. err := json.Unmarshal(jsondata, &i)
  32. if err != nil {
  33. // do something
  34. }
  35. x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc")
  36. if err != nil {
  37. // do something else
  38. }
  39. fmt.Println(string(x))
  40. }
  41. output:
  42. <mydoc>
  43. <somekey>somevalue</somekey>
  44. <element>string</element>
  45. <element>3.14159265</element>
  46. <element>true</element>
  47. </mydoc>
  48. */
  49. // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
  50. // AnyXml( v, myRootTag, myElementTag).
  51. func AnyXml(v interface{}, tags ...string) ([]byte, error) {
  52. var rt, et string
  53. if len(tags) == 1 || len(tags) == 2 {
  54. rt = tags[0]
  55. } else {
  56. rt = DefaultRootTag
  57. }
  58. if len(tags) == 2 {
  59. et = tags[1]
  60. } else {
  61. et = DefaultElementTag
  62. }
  63. if v == nil {
  64. if useGoXmlEmptyElemSyntax {
  65. return []byte("<" + rt + "></" + rt + ">"), nil
  66. }
  67. return []byte("<" + rt + "/>"), nil
  68. }
  69. if reflect.TypeOf(v).Kind() == reflect.Struct {
  70. return xml.Marshal(v)
  71. }
  72. var err error
  73. s := new(bytes.Buffer)
  74. p := new(pretty)
  75. var b []byte
  76. switch v.(type) {
  77. case []interface{}:
  78. if _, err = s.WriteString("<" + rt + ">"); err != nil {
  79. return nil, err
  80. }
  81. for _, vv := range v.([]interface{}) {
  82. switch vv.(type) {
  83. case map[string]interface{}:
  84. m := vv.(map[string]interface{})
  85. if len(m) == 1 {
  86. for tag, val := range m {
  87. err = marshalMapToXmlIndent(false, s, tag, val, p)
  88. }
  89. } else {
  90. err = marshalMapToXmlIndent(false, s, et, vv, p)
  91. }
  92. default:
  93. err = marshalMapToXmlIndent(false, s, et, vv, p)
  94. }
  95. if err != nil {
  96. break
  97. }
  98. }
  99. if _, err = s.WriteString("</" + rt + ">"); err != nil {
  100. return nil, err
  101. }
  102. b = s.Bytes()
  103. case map[string]interface{}:
  104. m := Map(v.(map[string]interface{}))
  105. b, err = m.Xml(rt)
  106. default:
  107. err = marshalMapToXmlIndent(false, s, rt, v, p)
  108. b = s.Bytes()
  109. }
  110. return b, err
  111. }
  112. // Encode an arbitrary value as a pretty XML string.
  113. // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
  114. // AnyXmlIndent( v, "", " ", myRootTag, myElementTag).
  115. func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) {
  116. var rt, et string
  117. if len(tags) == 1 || len(tags) == 2 {
  118. rt = tags[0]
  119. } else {
  120. rt = DefaultRootTag
  121. }
  122. if len(tags) == 2 {
  123. et = tags[1]
  124. } else {
  125. et = DefaultElementTag
  126. }
  127. if v == nil {
  128. if useGoXmlEmptyElemSyntax {
  129. return []byte(prefix + "<" + rt + "></" + rt + ">"), nil
  130. }
  131. return []byte(prefix + "<" + rt + "/>"), nil
  132. }
  133. if reflect.TypeOf(v).Kind() == reflect.Struct {
  134. return xml.MarshalIndent(v, prefix, indent)
  135. }
  136. var err error
  137. s := new(bytes.Buffer)
  138. p := new(pretty)
  139. p.indent = indent
  140. p.padding = prefix
  141. var b []byte
  142. switch v.(type) {
  143. case []interface{}:
  144. if _, err = s.WriteString("<" + rt + ">\n"); err != nil {
  145. return nil, err
  146. }
  147. p.Indent()
  148. for _, vv := range v.([]interface{}) {
  149. switch vv.(type) {
  150. case map[string]interface{}:
  151. m := vv.(map[string]interface{})
  152. if len(m) == 1 {
  153. for tag, val := range m {
  154. err = marshalMapToXmlIndent(true, s, tag, val, p)
  155. }
  156. } else {
  157. p.start = 1 // we 1 tag in
  158. err = marshalMapToXmlIndent(true, s, et, vv, p)
  159. // *s += "\n"
  160. if _, err = s.WriteString("\n"); err != nil {
  161. return nil, err
  162. }
  163. }
  164. default:
  165. p.start = 0 // in case trailing p.start = 1
  166. err = marshalMapToXmlIndent(true, s, et, vv, p)
  167. }
  168. if err != nil {
  169. break
  170. }
  171. }
  172. if _, err = s.WriteString(`</` + rt + `>`); err != nil {
  173. return nil, err
  174. }
  175. b = s.Bytes()
  176. case map[string]interface{}:
  177. m := Map(v.(map[string]interface{}))
  178. b, err = m.XmlIndent(prefix, indent, rt)
  179. default:
  180. err = marshalMapToXmlIndent(true, s, rt, v, p)
  181. b = s.Bytes()
  182. }
  183. return b, err
  184. }