Blame vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go

Packit Service 4d2de5
package xmlutil
Packit Service 4d2de5
Packit Service 4d2de5
import (
Packit Service 4d2de5
	"bytes"
Packit Service 4d2de5
	"encoding/base64"
Packit Service 4d2de5
	"encoding/xml"
Packit Service 4d2de5
	"fmt"
Packit Service 4d2de5
	"io"
Packit Service 4d2de5
	"reflect"
Packit Service 4d2de5
	"strconv"
Packit Service 4d2de5
	"strings"
Packit Service 4d2de5
	"time"
Packit Service 4d2de5
Packit Service 4d2de5
	"github.com/aws/aws-sdk-go/aws/awserr"
Packit Service 4d2de5
	"github.com/aws/aws-sdk-go/private/protocol"
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
// UnmarshalXMLError unmarshals the XML error from the stream into the value
Packit Service 4d2de5
// type specified. The value must be a pointer. If the message fails to
Packit Service 4d2de5
// unmarshal, the message content will be included in the returned error as a
Packit Service 4d2de5
// awserr.UnmarshalError.
Packit Service 4d2de5
func UnmarshalXMLError(v interface{}, stream io.Reader) error {
Packit Service 4d2de5
	var errBuf bytes.Buffer
Packit Service 4d2de5
	body := io.TeeReader(stream, &errBuf)
Packit Service 4d2de5
Packit Service 4d2de5
	err := xml.NewDecoder(body).Decode(v)
Packit Service 4d2de5
	if err != nil && err != io.EOF {
Packit Service 4d2de5
		return awserr.NewUnmarshalError(err,
Packit Service 4d2de5
			"failed to unmarshal error message", errBuf.Bytes())
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// UnmarshalXML deserializes an xml.Decoder into the container v. V
Packit Service 4d2de5
// needs to match the shape of the XML expected to be decoded.
Packit Service 4d2de5
// If the shape doesn't match unmarshaling will fail.
Packit Service 4d2de5
func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
Packit Service 4d2de5
	n, err := XMLToStruct(d, nil)
Packit Service 4d2de5
	if err != nil {
Packit Service 4d2de5
		return err
Packit Service 4d2de5
	}
Packit Service 4d2de5
	if n.Children != nil {
Packit Service 4d2de5
		for _, root := range n.Children {
Packit Service 4d2de5
			for _, c := range root {
Packit Service 4d2de5
				if wrappedChild, ok := c.Children[wrapper]; ok {
Packit Service 4d2de5
					c = wrappedChild[0] // pull out wrapped element
Packit Service 4d2de5
				}
Packit Service 4d2de5
Packit Service 4d2de5
				err = parse(reflect.ValueOf(v), c, "")
Packit Service 4d2de5
				if err != nil {
Packit Service 4d2de5
					if err == io.EOF {
Packit Service 4d2de5
						return nil
Packit Service 4d2de5
					}
Packit Service 4d2de5
					return err
Packit Service 4d2de5
				}
Packit Service 4d2de5
			}
Packit Service 4d2de5
		}
Packit Service 4d2de5
		return nil
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
Packit Service 4d2de5
// will be used to determine the type from r.
Packit Service 4d2de5
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	rtype := r.Type()
Packit Service 4d2de5
	if rtype.Kind() == reflect.Ptr {
Packit Service 4d2de5
		rtype = rtype.Elem() // check kind of actual element type
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	t := tag.Get("type")
Packit Service 4d2de5
	if t == "" {
Packit Service 4d2de5
		switch rtype.Kind() {
Packit Service 4d2de5
		case reflect.Struct:
Packit Service 4d2de5
			// also it can't be a time object
Packit Service 4d2de5
			if _, ok := r.Interface().(*time.Time); !ok {
Packit Service 4d2de5
				t = "structure"
Packit Service 4d2de5
			}
Packit Service 4d2de5
		case reflect.Slice:
Packit Service 4d2de5
			// also it can't be a byte slice
Packit Service 4d2de5
			if _, ok := r.Interface().([]byte); !ok {
Packit Service 4d2de5
				t = "list"
Packit Service 4d2de5
			}
Packit Service 4d2de5
		case reflect.Map:
Packit Service 4d2de5
			t = "map"
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	switch t {
Packit Service 4d2de5
	case "structure":
Packit Service 4d2de5
		if field, ok := rtype.FieldByName("_"); ok {
Packit Service 4d2de5
			tag = field.Tag
Packit Service 4d2de5
		}
Packit Service 4d2de5
		return parseStruct(r, node, tag)
Packit Service 4d2de5
	case "list":
Packit Service 4d2de5
		return parseList(r, node, tag)
Packit Service 4d2de5
	case "map":
Packit Service 4d2de5
		return parseMap(r, node, tag)
Packit Service 4d2de5
	default:
Packit Service 4d2de5
		return parseScalar(r, node, tag)
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
Packit Service 4d2de5
// types in the structure will also be deserialized.
Packit Service 4d2de5
func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	t := r.Type()
Packit Service 4d2de5
	if r.Kind() == reflect.Ptr {
Packit Service 4d2de5
		if r.IsNil() { // create the structure if it's nil
Packit Service 4d2de5
			s := reflect.New(r.Type().Elem())
Packit Service 4d2de5
			r.Set(s)
Packit Service 4d2de5
			r = s
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		r = r.Elem()
Packit Service 4d2de5
		t = t.Elem()
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	// unwrap any payloads
Packit Service 4d2de5
	if payload := tag.Get("payload"); payload != "" {
Packit Service 4d2de5
		field, _ := t.FieldByName(payload)
Packit Service 4d2de5
		return parseStruct(r.FieldByName(payload), node, field.Tag)
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	for i := 0; i < t.NumField(); i++ {
Packit Service 4d2de5
		field := t.Field(i)
Packit Service 4d2de5
		if c := field.Name[0:1]; strings.ToLower(c) == c {
Packit Service 4d2de5
			continue // ignore unexported fields
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		// figure out what this field is called
Packit Service 4d2de5
		name := field.Name
Packit Service 4d2de5
		if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
Packit Service 4d2de5
			name = field.Tag.Get("locationNameList")
Packit Service 4d2de5
		} else if locName := field.Tag.Get("locationName"); locName != "" {
Packit Service 4d2de5
			name = locName
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		// try to find the field by name in elements
Packit Service 4d2de5
		elems := node.Children[name]
Packit Service 4d2de5
Packit Service 4d2de5
		if elems == nil { // try to find the field in attributes
Packit Service 4d2de5
			if val, ok := node.findElem(name); ok {
Packit Service 4d2de5
				elems = []*XMLNode{{Text: val}}
Packit Service 4d2de5
			}
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		member := r.FieldByName(field.Name)
Packit Service 4d2de5
		for _, elem := range elems {
Packit Service 4d2de5
			err := parse(member, elem, field.Tag)
Packit Service 4d2de5
			if err != nil {
Packit Service 4d2de5
				return err
Packit Service 4d2de5
			}
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parseList deserializes a list of values from an XML node. Each list entry
Packit Service 4d2de5
// will also be deserialized.
Packit Service 4d2de5
func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	t := r.Type()
Packit Service 4d2de5
Packit Service 4d2de5
	if tag.Get("flattened") == "" { // look at all item entries
Packit Service 4d2de5
		mname := "member"
Packit Service 4d2de5
		if name := tag.Get("locationNameList"); name != "" {
Packit Service 4d2de5
			mname = name
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		if Children, ok := node.Children[mname]; ok {
Packit Service 4d2de5
			if r.IsNil() {
Packit Service 4d2de5
				r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
Packit Service 4d2de5
			}
Packit Service 4d2de5
Packit Service 4d2de5
			for i, c := range Children {
Packit Service 4d2de5
				err := parse(r.Index(i), c, "")
Packit Service 4d2de5
				if err != nil {
Packit Service 4d2de5
					return err
Packit Service 4d2de5
				}
Packit Service 4d2de5
			}
Packit Service 4d2de5
		}
Packit Service 4d2de5
	} else { // flattened list means this is a single element
Packit Service 4d2de5
		if r.IsNil() {
Packit Service 4d2de5
			r.Set(reflect.MakeSlice(t, 0, 0))
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		childR := reflect.Zero(t.Elem())
Packit Service 4d2de5
		r.Set(reflect.Append(r, childR))
Packit Service 4d2de5
		err := parse(r.Index(r.Len()-1), node, "")
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
Packit Service 4d2de5
// will also be deserialized as map entries.
Packit Service 4d2de5
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	if r.IsNil() {
Packit Service 4d2de5
		r.Set(reflect.MakeMap(r.Type()))
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	if tag.Get("flattened") == "" { // look at all child entries
Packit Service 4d2de5
		for _, entry := range node.Children["entry"] {
Packit Service 4d2de5
			parseMapEntry(r, entry, tag)
Packit Service 4d2de5
		}
Packit Service 4d2de5
	} else { // this element is itself an entry
Packit Service 4d2de5
		parseMapEntry(r, node, tag)
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parseMapEntry deserializes a map entry from a XML node.
Packit Service 4d2de5
func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	kname, vname := "key", "value"
Packit Service 4d2de5
	if n := tag.Get("locationNameKey"); n != "" {
Packit Service 4d2de5
		kname = n
Packit Service 4d2de5
	}
Packit Service 4d2de5
	if n := tag.Get("locationNameValue"); n != "" {
Packit Service 4d2de5
		vname = n
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	keys, ok := node.Children[kname]
Packit Service 4d2de5
	values := node.Children[vname]
Packit Service 4d2de5
	if ok {
Packit Service 4d2de5
		for i, key := range keys {
Packit Service 4d2de5
			keyR := reflect.ValueOf(key.Text)
Packit Service 4d2de5
			value := values[i]
Packit Service 4d2de5
			valueR := reflect.New(r.Type().Elem()).Elem()
Packit Service 4d2de5
Packit Service 4d2de5
			parse(valueR, value, "")
Packit Service 4d2de5
			r.SetMapIndex(keyR, valueR)
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// parseScaller deserializes an XMLNode value into a concrete type based on the
Packit Service 4d2de5
// interface type of r.
Packit Service 4d2de5
//
Packit Service 4d2de5
// Error is returned if the deserialization fails due to invalid type conversion,
Packit Service 4d2de5
// or unsupported interface type.
Packit Service 4d2de5
func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
Packit Service 4d2de5
	switch r.Interface().(type) {
Packit Service 4d2de5
	case *string:
Packit Service 4d2de5
		r.Set(reflect.ValueOf(&node.Text))
Packit Service 4d2de5
		return nil
Packit Service 4d2de5
	case []byte:
Packit Service 4d2de5
		b, err := base64.StdEncoding.DecodeString(node.Text)
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
		r.Set(reflect.ValueOf(b))
Packit Service 4d2de5
	case *bool:
Packit Service 4d2de5
		v, err := strconv.ParseBool(node.Text)
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
		r.Set(reflect.ValueOf(&v))
Packit Service 4d2de5
	case *int64:
Packit Service 4d2de5
		v, err := strconv.ParseInt(node.Text, 10, 64)
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
		r.Set(reflect.ValueOf(&v))
Packit Service 4d2de5
	case *float64:
Packit Service 4d2de5
		v, err := strconv.ParseFloat(node.Text, 64)
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
		r.Set(reflect.ValueOf(&v))
Packit Service 4d2de5
	case *time.Time:
Packit Service 4d2de5
		format := tag.Get("timestampFormat")
Packit Service 4d2de5
		if len(format) == 0 {
Packit Service 4d2de5
			format = protocol.ISO8601TimeFormatName
Packit Service 4d2de5
		}
Packit Service 4d2de5
Packit Service 4d2de5
		t, err := protocol.ParseTime(format, node.Text)
Packit Service 4d2de5
		if err != nil {
Packit Service 4d2de5
			return err
Packit Service 4d2de5
		}
Packit Service 4d2de5
		r.Set(reflect.ValueOf(&t))
Packit Service 4d2de5
	default:
Packit Service 4d2de5
		return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return nil
Packit Service 4d2de5
}