summaryrefslogtreecommitdiff
path: root/libgo/go/encoding/xml/read.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/encoding/xml/read.go')
-rw-r--r--libgo/go/encoding/xml/read.go92
1 files changed, 65 insertions, 27 deletions
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index 937432e3a7e..5a89d5f504a 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -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.
@@ -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,8 +99,12 @@ 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.
@@ -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,30 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
}
}
- copyValue(val, []byte(attr.Value))
- return nil
+ 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
+ }
+
+ return copyValue(val, []byte(attr.Value))
}
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 +386,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 +433,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 +582,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