diff options
Diffstat (limited to 'libgo/go/encoding/xml/read.go')
-rw-r--r-- | libgo/go/encoding/xml/read.go | 109 |
1 files changed, 74 insertions, 35 deletions
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 77b4c7b495..799b57e9d1 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -27,7 +27,7 @@ import ( // discarded. // // Because Unmarshal uses the reflect package, it can only assign -// to exported (upper case) fields. Unmarshal uses a case-sensitive +// to exported (upper case) fields. Unmarshal uses a case-sensitive // comparison to match XML element names to tag values and struct // field names. // @@ -37,9 +37,9 @@ import ( // // * If the struct has a field of type []byte or string with tag // ",innerxml", Unmarshal accumulates the raw XML nested inside the -// element in that field. The rest of the rules still apply. +// element in that field. The rest of the rules still apply. // -// * If the struct has a field named XMLName of type xml.Name, +// * If the struct has a field named XMLName of type Name, // Unmarshal records the element name in that field. // // * If the XMLName field has an associated tag of the form @@ -52,6 +52,11 @@ import ( // the explicit name in a struct field tag of the form "name,attr", // Unmarshal records the attribute value in that field. // +// * If the XML element has an attribute not handled by the previous +// rule and the struct has a field with an associated tag containing +// ",any,attr", Unmarshal records the attribute value in the first +// such field. +// // * If the XML element contains character data, that data is // accumulated in the first struct field that has tag ",chardata". // The struct field may have type []byte or string. @@ -59,7 +64,7 @@ import ( // // * If the XML element contains comments, they are accumulated in // the first struct field that has tag ",comment". The struct -// field may have type []byte or string. If there is no such +// field may have type []byte or string. If there is no such // field, the comments are discarded. // // * If the XML element contains a sub-element whose name matches @@ -85,7 +90,7 @@ import ( // * An anonymous struct field is handled as if the fields of its // value were part of the outer struct. // -// * A struct field with tag "-" is never unmarshalled into. +// * A struct field with tag "-" is never unmarshaled into. // // Unmarshal maps an XML element to a string or []byte by saving the // concatenation of that element's character data in the string or @@ -94,19 +99,23 @@ import ( // Unmarshal maps an attribute value to a string or []byte by saving // the value in the string or slice. // -// Unmarshal maps an XML element to a slice by extending the length of -// the slice and mapping the element to the newly created value. +// Unmarshal maps an attribute value to an Attr by saving the attribute, +// including its name, in the Attr. +// +// Unmarshal maps an XML element or attribute value to a slice by +// extending the length of the slice and mapping the element or attribute +// to the newly created value. // // Unmarshal maps an XML element or attribute value to a bool by // setting it to the boolean value represented by the string. // // Unmarshal maps an XML element or attribute value to an integer or // floating-point field by setting the field to the result of -// interpreting the string value in decimal. There is no check for +// interpreting the string value in decimal. There is no check for // overflow. // -// Unmarshal maps an XML element to an xml.Name by recording the -// element name. +// Unmarshal maps an XML element to a Name by recording the element +// name. // // Unmarshal maps an XML element to a pointer by setting the pointer // to a freshly allocated value and then mapping the element to that value. @@ -115,13 +124,13 @@ func Unmarshal(data []byte, v interface{}) error { return NewDecoder(bytes.NewReader(data)).Decode(v) } -// Decode works like xml.Unmarshal, except it reads the decoder +// Decode works like Unmarshal, except it reads the decoder // stream to find the start element. func (d *Decoder) Decode(v interface{}) error { return d.DecodeElement(v, nil) } -// DecodeElement works like xml.Unmarshal except that it takes +// DecodeElement works like Unmarshal except that it takes // a pointer to the start XML element to decode into v. // It is useful when a client reads some raw XML tokens itself // but also wants to defer to Unmarshal for some elements. @@ -133,7 +142,7 @@ func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { return d.unmarshal(val.Elem(), start) } -// An UnmarshalError represents an error in the unmarshalling process. +// An UnmarshalError represents an error in the unmarshaling process. type UnmarshalError string func (e UnmarshalError) Error() string { return string(e) } @@ -232,7 +241,6 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { } val = val.Elem() } - if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. @@ -258,11 +266,31 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { } } + if val.Type().Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 { + // Slice of element values. + // Grow slice. + n := val.Len() + val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem()))) + + // Recur to read element into slice. + if err := p.unmarshalAttr(val.Index(n), attr); err != nil { + val.SetLen(n) + return err + } + return nil + } + + if val.Type() == attrType { + val.Set(reflect.ValueOf(attr)) + return nil + } + copyValue(val, []byte(attr.Value)) return nil } var ( + attrType = reflect.TypeOf(Attr{}) unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() @@ -359,16 +387,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // 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) + v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem()))) // Recur to read element into slice. if err := p.unmarshal(v.Index(n), start); err != nil { @@ -415,22 +434,40 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { } // Assign attributes. - // Also, determine whether we need to save character data or comments. - for i := range tinfo.fields { - finfo := &tinfo.fields[i] - switch finfo.flags & fMode { - case fAttr: - strv := finfo.value(sv) - // Look for attribute. - for _, a := range start.Attr { + for _, a := range start.Attr { + handled := false + any := -1 + for i := range tinfo.fields { + finfo := &tinfo.fields[i] + switch finfo.flags & fMode { + case fAttr: + strv := finfo.value(sv) if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { if err := p.unmarshalAttr(strv, a); err != nil { return err } - break + handled = true } + + case fAny | fAttr: + if any == -1 { + any = i + } + } + } + if !handled && any >= 0 { + finfo := &tinfo.fields[any] + strv := finfo.value(sv) + if err := p.unmarshalAttr(strv, a); err != nil { + return err } + } + } + // Determine whether we need to save character data or comments. + for i := range tinfo.fields { + finfo := &tinfo.fields[i] + switch finfo.flags & fMode { case fCDATA, fCharData: if !saveData.IsValid() { saveData = finfo.value(sv) @@ -546,7 +583,9 @@ Loop: case reflect.String: t.SetString(string(saveXMLData)) case reflect.Slice: - t.Set(reflect.ValueOf(saveXMLData)) + if t.Type().Elem().Kind() == reflect.Uint8 { + t.Set(reflect.ValueOf(saveXMLData)) + } } return nil |