anyxml.go 3.6 KB

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