diff --git a/CHANGELOG.md b/CHANGELOG.md index f09017c..9da5e4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.5.2 + +Bugfixes: +* Decoding a `` that is nested in `` with variable types (e.g mix of ints, bool, string and structs) (#84). +Structs will be decoded into a `map[string]any` type, as it's not possible to decode. + ## 0.5.1 Bugfixes: diff --git a/decode.go b/decode.go index 4ad0209..0d93769 100644 --- a/decode.go +++ b/decode.go @@ -142,13 +142,24 @@ func (d *StdDecoder) decodeValue(value *ResponseValue, field reflect.Value) erro // Struct decoding case len(value.Struct) != 0: fieldKind := field.Kind() + fieldType := field.Type() + + if fieldKind == reflect.Interface { + // Create a new map[string]any and assign it to field + fieldType = reflect.TypeOf(map[string]any{}) + fieldKind = reflect.Map + + field.Set(reflect.MakeMap(fieldType)) + field = field.Elem() // As the field is an interface, need to unwrap it + } + if fieldKind != reflect.Struct && fieldKind != reflect.Map { return fmt.Errorf(errFormatInvalidFieldTypeOrType, reflect.Struct.String(), reflect.Map.String(), fieldKind.String()) } // If we are targeting a map, it should be initialized if fieldKind == reflect.Map { - if kt := field.Type().Key().Kind(); kt != reflect.String { + if kt := fieldType.Key().Kind(); kt != reflect.String { return fmt.Errorf(errFormatInvalidMapKeyTypeForStruct, kt.String()) } @@ -160,7 +171,7 @@ func (d *StdDecoder) decodeValue(value *ResponseValue, field reflect.Value) erro for _, m := range value.Struct { if fieldKind == reflect.Map { mapKey := reflect.ValueOf(m.Name) - f := reflect.New(field.Type().Elem()).Elem() + f := reflect.New(fieldType.Elem()).Elem() if err := d.decodeValue(&m.Value, f); err != nil { return fmt.Errorf("failed decoding struct member '%s': %w", m.Name, err) diff --git a/decode_test.go b/decode_test.go index 4f216ba..8717ac6 100644 --- a/decode_test.go +++ b/decode_test.go @@ -622,6 +622,20 @@ func Test_structMemberToFieldName(t *testing.T) { } } +func Test_github(t *testing.T) { + dec := &StdDecoder{} + decodeTarget := struct { + Array []any + }{} + + err := dec.DecodeRaw(loadTestFile(t, "response_array_mixed_with_struct.xml"), &decodeTarget) + require.NoError(t, err) + require.Equal(t, 3, len(decodeTarget.Array)) + require.Equal(t, 200, decodeTarget.Array[0]) + require.Equal(t, "OK", decodeTarget.Array[1]) + require.Equal(t, "OK", decodeTarget.Array[2].(map[string]any)["status"]) +} + func loadTestFile(t *testing.T, name string) []byte { path := filepath.Join("testdata", name) // relative path diff --git a/testdata/response_array_mixed_with_struct.xml b/testdata/response_array_mixed_with_struct.xml new file mode 100644 index 0000000..a094900 --- /dev/null +++ b/testdata/response_array_mixed_with_struct.xml @@ -0,0 +1,29 @@ + + + + + + + + + 200 + + OK + + + + status + OK + + + contact + <sip:raf@192.168.164.128:5060>;expires=60 + + + + + + + + +