anyxml.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. An extreme example is available in examples/goofy_map.go.
  49. */
  50. // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
  51. // AnyXml( v, myRootTag, myElementTag).
  52. func AnyXml(v interface{}, tags ...string) ([]byte, error) {
  53. var rt, et string
  54. if len(tags) == 1 || len(tags) == 2 {
  55. rt = tags[0]
  56. } else {
  57. rt = DefaultRootTag
  58. }
  59. if len(tags) == 2 {
  60. et = tags[1]
  61. } else {
  62. et = DefaultElementTag
  63. }
  64. if v == nil {
  65. if useGoXmlEmptyElemSyntax {
  66. return []byte("<" + rt + "></" + rt + ">"), nil
  67. }
  68. return []byte("<" + rt + "/>"), nil
  69. }
  70. if reflect.TypeOf(v).Kind() == reflect.Struct {
  71. return xml.Marshal(v)
  72. }
  73. var err error
  74. s := new(bytes.Buffer)
  75. p := new(pretty)
  76. var b []byte
  77. switch v.(type) {
  78. case []interface{}:
  79. if _, err = s.WriteString("<" + rt + ">"); err != nil {
  80. return nil, err
  81. }
  82. for _, vv := range v.([]interface{}) {
  83. switch vv.(type) {
  84. case map[string]interface{}:
  85. m := vv.(map[string]interface{})
  86. if len(m) == 1 {
  87. for tag, val := range m {
  88. err = marshalMapToXmlIndent(false, s, tag, val, p)
  89. }
  90. } else {
  91. err = marshalMapToXmlIndent(false, s, et, vv, p)
  92. }
  93. default:
  94. err = marshalMapToXmlIndent(false, s, et, vv, p)
  95. }
  96. if err != nil {
  97. break
  98. }
  99. }
  100. if _, err = s.WriteString("</" + rt + ">"); err != nil {
  101. return nil, err
  102. }
  103. b = s.Bytes()
  104. case map[string]interface{}:
  105. m := Map(v.(map[string]interface{}))
  106. b, err = m.Xml(rt)
  107. default:
  108. err = marshalMapToXmlIndent(false, s, rt, v, p)
  109. b = s.Bytes()
  110. }
  111. return b, err
  112. }
  113. // Encode an arbitrary value as a pretty XML string.
  114. // Alternative values for DefaultRootTag and DefaultElementTag can be set as:
  115. // AnyXmlIndent( v, "", " ", myRootTag, myElementTag).
  116. func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) {
  117. var rt, et string
  118. if len(tags) == 1 || len(tags) == 2 {
  119. rt = tags[0]
  120. } else {
  121. rt = DefaultRootTag
  122. }
  123. if len(tags) == 2 {
  124. et = tags[1]
  125. } else {
  126. et = DefaultElementTag
  127. }
  128. if v == nil {
  129. if useGoXmlEmptyElemSyntax {
  130. return []byte(prefix + "<" + rt + "></" + rt + ">"), nil
  131. }
  132. return []byte(prefix + "<" + rt + "/>"), nil
  133. }
  134. if reflect.TypeOf(v).Kind() == reflect.Struct {
  135. return xml.MarshalIndent(v, prefix, indent)
  136. }
  137. var err error
  138. s := new(bytes.Buffer)
  139. p := new(pretty)
  140. p.indent = indent
  141. p.padding = prefix
  142. var b []byte
  143. switch v.(type) {
  144. case []interface{}:
  145. if _, err = s.WriteString("<" + rt + ">\n"); err != nil {
  146. return nil, err
  147. }
  148. p.Indent()
  149. for _, vv := range v.([]interface{}) {
  150. switch vv.(type) {
  151. case map[string]interface{}:
  152. m := vv.(map[string]interface{})
  153. if len(m) == 1 {
  154. for tag, val := range m {
  155. err = marshalMapToXmlIndent(true, s, tag, val, p)
  156. }
  157. } else {
  158. p.start = 1 // we 1 tag in
  159. err = marshalMapToXmlIndent(true, s, et, vv, p)
  160. // *s += "\n"
  161. if _, err = s.WriteString("\n"); err != nil {
  162. return nil, err
  163. }
  164. }
  165. default:
  166. p.start = 0 // in case trailing p.start = 1
  167. err = marshalMapToXmlIndent(true, s, et, vv, p)
  168. }
  169. if err != nil {
  170. break
  171. }
  172. }
  173. if _, err = s.WriteString(`</` + rt + `>`); err != nil {
  174. return nil, err
  175. }
  176. b = s.Bytes()
  177. case map[string]interface{}:
  178. m := Map(v.(map[string]interface{}))
  179. b, err = m.XmlIndent(prefix, indent, rt)
  180. default:
  181. err = marshalMapToXmlIndent(true, s, rt, v, p)
  182. b = s.Bytes()
  183. }
  184. return b, err
  185. }