anyxml.go raw
1 package mxj
2
3 import (
4 "bytes"
5 "encoding/xml"
6 "reflect"
7 )
8
9 const (
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
55 An 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).
59 func 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).
128 func 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