Commit 2156735a authored by Paul Warren's avatar Paul Warren
parent e7546450
......@@ -627,6 +627,51 @@ func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []str
Loop:
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
if finfo.flags&fAttr != 0 {
if len(finfo.parents) > len(parents)+1 {
recurse = true
parents = finfo.parents[:len(parents)+1]
} else if len(finfo.parents) == len(parents)+1 {
for _, a := range start.Attr {
if a.Name.Local == finfo.name {
v := sv.FieldByIndex(finfo.idx)
switch v.Kind() {
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
copyValue(v, []byte(a.Value))
continue Loop
case reflect.Slice:
typ := v.Type()
if typ.Elem().Kind() == reflect.Uint8 {
// []byte
copyValue(v, []byte(a.Value))
continue Loop
}
// Slice of element values.
// Grow slice.
n := v.Len()
if n >= v.Cap() {
ncap := 2 * n
if ncap < 4 {
ncap = 4
}
new := reflect.MakeSlice(typ, n, ncap)
reflect.Copy(new, v)
v.Set(new)
}
v.SetLen(n + 1)
// Recur to read element into slice.
copyValue(v.Index(n), []byte(a.Value))
continue Loop
default:
return false, errors.New("unknown type " + v.Type().String())
}
}
}
}
}
if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
continue
}
......
......@@ -207,7 +207,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
}
finfo.name = parents[len(parents)-1]
if len(parents) > 1 {
if (finfo.flags & fElement) == 0 {
if (finfo.flags & (fElement | fAttr)) == 0 {
return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ","))
}
finfo.parents = parents[:len(parents)-1]
......
......@@ -750,3 +750,92 @@ func TestIssue5880(t *testing.T) {
t.Errorf("Marshal generated invalid UTF-8: %x", data)
}
}
func TestNestedAttr(t *testing.T) {
type NestedAttr struct {
Version string `xml:"version,attr"`
AbName string `xml:"configuration>ab>name,attr"`
AbVariations int `xml:"configuration>ab>variations,attr"`
Example string `xml:"configuration>example"`
}
var a NestedAttr
err := Unmarshal([]byte(`
<rules version="1.0.1">
<configuration>
<ab name="ab test name" variations="5"/>
<example>example content</example>
</configuration>
</rules>
`), &a)
expectedNestedAttr := NestedAttr{
Version: "1.0.1",
AbName: "ab test name",
AbVariations: 5,
Example: "example content",
}
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(a, expectedNestedAttr) {
t.Errorf("have %+v want %+v", a, expectedNestedAttr)
}
}
func TestNestedList(t *testing.T) {
type NestedList struct {
Example string `xml:"example"`
Members []int `xml:"members>member"`
}
var a NestedList
err := Unmarshal([]byte(`
<output>
<example>example content</example>
<members>
<member>1</member>
<member>13</member>
<member>5</member>
</members>
</output>
`), &a)
expectedNestedList := NestedList{
Example: "example content",
Members: []int{1, 13, 5},
}
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(a, expectedNestedList) {
t.Errorf("have %+v want %+v", a, expectedNestedList)
}
}
func TestNestedAttrList(t *testing.T) {
type NestedAttrList struct {
Example string `xml:"example"`
Members []int `xml:"members>member>id,attr"`
}
var a NestedAttrList
err := Unmarshal([]byte(`
<output>
<example>example content</example>
<members>
<member id="1"/>
<member id="13"/>
<member id="5"/>
</members>
</output>
`), &a)
expectedNestedAttrList := NestedAttrList{
Example: "example content",
Members: []int{1, 13, 5},
}
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(a, expectedNestedAttrList) {
t.Errorf("have %+v want %+v", a, expectedNestedAttrList)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment