]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / private / protocol / xml / xmlutil / unmarshal.go
1 package xmlutil
2
3 import (
4 "encoding/base64"
5 "encoding/xml"
6 "fmt"
7 "io"
8 "reflect"
9 "strconv"
10 "strings"
11 "time"
12 )
13
14 // UnmarshalXML deserializes an xml.Decoder into the container v. V
15 // needs to match the shape of the XML expected to be decoded.
16 // If the shape doesn't match unmarshaling will fail.
17 func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
18 n, err := XMLToStruct(d, nil)
19 if err != nil {
20 return err
21 }
22 if n.Children != nil {
23 for _, root := range n.Children {
24 for _, c := range root {
25 if wrappedChild, ok := c.Children[wrapper]; ok {
26 c = wrappedChild[0] // pull out wrapped element
27 }
28
29 err = parse(reflect.ValueOf(v), c, "")
30 if err != nil {
31 if err == io.EOF {
32 return nil
33 }
34 return err
35 }
36 }
37 }
38 return nil
39 }
40 return nil
41 }
42
43 // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
44 // will be used to determine the type from r.
45 func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
46 rtype := r.Type()
47 if rtype.Kind() == reflect.Ptr {
48 rtype = rtype.Elem() // check kind of actual element type
49 }
50
51 t := tag.Get("type")
52 if t == "" {
53 switch rtype.Kind() {
54 case reflect.Struct:
55 t = "structure"
56 case reflect.Slice:
57 t = "list"
58 case reflect.Map:
59 t = "map"
60 }
61 }
62
63 switch t {
64 case "structure":
65 if field, ok := rtype.FieldByName("_"); ok {
66 tag = field.Tag
67 }
68 return parseStruct(r, node, tag)
69 case "list":
70 return parseList(r, node, tag)
71 case "map":
72 return parseMap(r, node, tag)
73 default:
74 return parseScalar(r, node, tag)
75 }
76 }
77
78 // parseStruct deserializes a structure and its fields from an XMLNode. Any nested
79 // types in the structure will also be deserialized.
80 func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
81 t := r.Type()
82 if r.Kind() == reflect.Ptr {
83 if r.IsNil() { // create the structure if it's nil
84 s := reflect.New(r.Type().Elem())
85 r.Set(s)
86 r = s
87 }
88
89 r = r.Elem()
90 t = t.Elem()
91 }
92
93 // unwrap any payloads
94 if payload := tag.Get("payload"); payload != "" {
95 field, _ := t.FieldByName(payload)
96 return parseStruct(r.FieldByName(payload), node, field.Tag)
97 }
98
99 for i := 0; i < t.NumField(); i++ {
100 field := t.Field(i)
101 if c := field.Name[0:1]; strings.ToLower(c) == c {
102 continue // ignore unexported fields
103 }
104
105 // figure out what this field is called
106 name := field.Name
107 if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
108 name = field.Tag.Get("locationNameList")
109 } else if locName := field.Tag.Get("locationName"); locName != "" {
110 name = locName
111 }
112
113 // try to find the field by name in elements
114 elems := node.Children[name]
115
116 if elems == nil { // try to find the field in attributes
117 if val, ok := node.findElem(name); ok {
118 elems = []*XMLNode{{Text: val}}
119 }
120 }
121
122 member := r.FieldByName(field.Name)
123 for _, elem := range elems {
124 err := parse(member, elem, field.Tag)
125 if err != nil {
126 return err
127 }
128 }
129 }
130 return nil
131 }
132
133 // parseList deserializes a list of values from an XML node. Each list entry
134 // will also be deserialized.
135 func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
136 t := r.Type()
137
138 if tag.Get("flattened") == "" { // look at all item entries
139 mname := "member"
140 if name := tag.Get("locationNameList"); name != "" {
141 mname = name
142 }
143
144 if Children, ok := node.Children[mname]; ok {
145 if r.IsNil() {
146 r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
147 }
148
149 for i, c := range Children {
150 err := parse(r.Index(i), c, "")
151 if err != nil {
152 return err
153 }
154 }
155 }
156 } else { // flattened list means this is a single element
157 if r.IsNil() {
158 r.Set(reflect.MakeSlice(t, 0, 0))
159 }
160
161 childR := reflect.Zero(t.Elem())
162 r.Set(reflect.Append(r, childR))
163 err := parse(r.Index(r.Len()-1), node, "")
164 if err != nil {
165 return err
166 }
167 }
168
169 return nil
170 }
171
172 // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
173 // will also be deserialized as map entries.
174 func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
175 if r.IsNil() {
176 r.Set(reflect.MakeMap(r.Type()))
177 }
178
179 if tag.Get("flattened") == "" { // look at all child entries
180 for _, entry := range node.Children["entry"] {
181 parseMapEntry(r, entry, tag)
182 }
183 } else { // this element is itself an entry
184 parseMapEntry(r, node, tag)
185 }
186
187 return nil
188 }
189
190 // parseMapEntry deserializes a map entry from a XML node.
191 func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
192 kname, vname := "key", "value"
193 if n := tag.Get("locationNameKey"); n != "" {
194 kname = n
195 }
196 if n := tag.Get("locationNameValue"); n != "" {
197 vname = n
198 }
199
200 keys, ok := node.Children[kname]
201 values := node.Children[vname]
202 if ok {
203 for i, key := range keys {
204 keyR := reflect.ValueOf(key.Text)
205 value := values[i]
206 valueR := reflect.New(r.Type().Elem()).Elem()
207
208 parse(valueR, value, "")
209 r.SetMapIndex(keyR, valueR)
210 }
211 }
212 return nil
213 }
214
215 // parseScaller deserializes an XMLNode value into a concrete type based on the
216 // interface type of r.
217 //
218 // Error is returned if the deserialization fails due to invalid type conversion,
219 // or unsupported interface type.
220 func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
221 switch r.Interface().(type) {
222 case *string:
223 r.Set(reflect.ValueOf(&node.Text))
224 return nil
225 case []byte:
226 b, err := base64.StdEncoding.DecodeString(node.Text)
227 if err != nil {
228 return err
229 }
230 r.Set(reflect.ValueOf(b))
231 case *bool:
232 v, err := strconv.ParseBool(node.Text)
233 if err != nil {
234 return err
235 }
236 r.Set(reflect.ValueOf(&v))
237 case *int64:
238 v, err := strconv.ParseInt(node.Text, 10, 64)
239 if err != nil {
240 return err
241 }
242 r.Set(reflect.ValueOf(&v))
243 case *float64:
244 v, err := strconv.ParseFloat(node.Text, 64)
245 if err != nil {
246 return err
247 }
248 r.Set(reflect.ValueOf(&v))
249 case *time.Time:
250 const ISO8601UTC = "2006-01-02T15:04:05Z"
251 t, err := time.Parse(ISO8601UTC, node.Text)
252 if err != nil {
253 return err
254 }
255 r.Set(reflect.ValueOf(&t))
256 default:
257 return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
258 }
259 return nil
260 }