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