diff options
Diffstat (limited to 'libgo/go/encoding/xml')
-rw-r--r-- | libgo/go/encoding/xml/marshal.go | 19 | ||||
-rw-r--r-- | libgo/go/encoding/xml/marshal_test.go | 97 | ||||
-rw-r--r-- | libgo/go/encoding/xml/read.go | 56 | ||||
-rw-r--r-- | libgo/go/encoding/xml/read_test.go | 44 | ||||
-rw-r--r-- | libgo/go/encoding/xml/typeinfo.go | 3 |
5 files changed, 175 insertions, 44 deletions
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 17134c5eb4d..aacb50c9cfc 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -241,7 +241,7 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p.WriteString(strconv.FormatUint(val.Uint(), 10)) case reflect.Float32, reflect.Float64: - p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64)) + p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits())) case reflect.String: // TODO: Add EscapeString. Escape(p, []byte(val.String())) @@ -273,19 +273,32 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { s := parentStack{printer: p} for i := range tinfo.fields { finfo := &tinfo.fields[i] - if finfo.flags&(fAttr|fAny) != 0 { + if finfo.flags&(fAttr) != 0 { continue } vf := finfo.value(val) switch finfo.flags & fMode { case fCharData: + var scratch [64]byte switch vf.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)) + case reflect.Float32, reflect.Float64: + Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())) + case reflect.Bool: + Escape(p, strconv.AppendBool(scratch[:0], vf.Bool())) case reflect.String: Escape(p, []byte(vf.String())) case reflect.Slice: if elem, ok := vf.Interface().([]byte); ok { Escape(p, elem) } + case reflect.Struct: + if vf.Type() == timeType { + Escape(p, []byte(vf.Interface().(time.Time).Format(time.RFC3339Nano))) + } } continue @@ -340,7 +353,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { continue } - case fElement: + case fElement, fElement | fAny: s.trim(finfo.parents) if len(finfo.parents) > len(s.stack) { if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() { diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index 668fea6f85e..67fcfd9ed56 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -59,6 +59,36 @@ type Book struct { Title string `xml:",chardata"` } +type Event struct { + XMLName struct{} `xml:"event"` + Year int `xml:",chardata"` +} + +type Movie struct { + XMLName struct{} `xml:"movie"` + Length uint `xml:",chardata"` +} + +type Pi struct { + XMLName struct{} `xml:"pi"` + Approximation float32 `xml:",chardata"` +} + +type Universe struct { + XMLName struct{} `xml:"universe"` + Visible float64 `xml:",chardata"` +} + +type Particle struct { + XMLName struct{} `xml:"particle"` + HasMass bool `xml:",chardata"` +} + +type Departure struct { + XMLName struct{} `xml:"departure"` + When time.Time `xml:",chardata"` +} + type SecretAgent struct { XMLName struct{} `xml:"agent"` Handle string `xml:"handle,attr"` @@ -188,6 +218,18 @@ type AnyTest struct { AnyField AnyHolder `xml:",any"` } +type AnyOmitTest struct { + XMLName struct{} `xml:"a"` + Nested string `xml:"nested>value"` + AnyField *AnyHolder `xml:",any,omitempty"` +} + +type AnySliceTest struct { + XMLName struct{} `xml:"a"` + Nested string `xml:"nested>value"` + AnyField []AnyHolder `xml:",any"` +} + type AnyHolder struct { XMLName Name XML string `xml:",innerxml"` @@ -333,6 +375,12 @@ var marshalTests = []struct { {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`}, {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`}, {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride & Prejudice</book>`}, + {Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`}, + {Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`}, + {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`}, + {Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`}, + {Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`}, + {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`}, {Value: atomValue, ExpectXML: atomXml}, { Value: &Ship{ @@ -652,12 +700,43 @@ var marshalTests = []struct { XML: "<sub>unknown</sub>", }, }, - UnmarshalOnly: true, }, { - Value: &AnyTest{Nested: "known", AnyField: AnyHolder{XML: "<unknown/>"}}, - ExpectXML: `<a><nested><value>known</value></nested></a>`, - MarshalOnly: true, + Value: &AnyTest{Nested: "known", + AnyField: AnyHolder{ + XML: "<unknown/>", + XMLName: Name{Local: "AnyField"}, + }, + }, + ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`, + }, + { + ExpectXML: `<a><nested><value>b</value></nested></a>`, + Value: &AnyOmitTest{ + Nested: "b", + }, + }, + { + ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`, + Value: &AnySliceTest{ + Nested: "b", + AnyField: []AnyHolder{ + { + XMLName: Name{Local: "c"}, + XML: "<d>e</d>", + }, + { + XMLName: Name{Space: "f", Local: "g"}, + XML: "<h>i</h>", + }, + }, + }, + }, + { + ExpectXML: `<a><nested><value>b</value></nested></a>`, + Value: &AnySliceTest{ + Nested: "b", + }, }, // Test recursive types. @@ -690,15 +769,17 @@ var marshalTests = []struct { // Test escaping. { - ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested></a>`, + ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested><empty></empty></a>`, Value: &AnyTest{ - Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`, + Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`, + AnyField: AnyHolder{XMLName: Name{Local: "empty"}}, }, }, { - ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested></a>`, + ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested><AnyField></AnyField></a>`, Value: &AnyTest{ - Nested: "newline: \n; cr: \r; tab: \t;", + Nested: "newline: \n; cr: \r; tab: \t;", + AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}}, }, }, { diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 0e6761d66ad..344ab514e37 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -279,7 +279,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { saveComment = finfo.value(sv) } - case fAny: + case fAny, fAny | fElement: if !saveAny.IsValid() { saveAny = finfo.value(sv) } @@ -374,68 +374,58 @@ Loop: } func copyValue(dst reflect.Value, src []byte) (err error) { - // Helper functions for integer and unsigned integer conversions - var itmp int64 - getInt64 := func() bool { - itmp, err = strconv.ParseInt(string(src), 10, 64) - // TODO: should check sizes - return err == nil - } - var utmp uint64 - getUint64 := func() bool { - utmp, err = strconv.ParseUint(string(src), 10, 64) - // TODO: check for overflow? - return err == nil - } - var ftmp float64 - getFloat64 := func() bool { - ftmp, err = strconv.ParseFloat(string(src), 64) - // TODO: check for overflow? - return err == nil + if dst.Kind() == reflect.Ptr { + if dst.IsNil() { + dst.Set(reflect.New(dst.Type().Elem())) + } + dst = dst.Elem() } // Save accumulated data. - switch t := dst; t.Kind() { + switch dst.Kind() { case reflect.Invalid: - // Probably a comment. + // Probably a commendst. default: - return errors.New("cannot happen: unknown type " + t.Type().String()) + return errors.New("cannot happen: unknown type " + dst.Type().String()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if !getInt64() { + itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits()) + if err != nil { return err } - t.SetInt(itmp) + dst.SetInt(itmp) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if !getUint64() { + utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits()) + if err != nil { return err } - t.SetUint(utmp) + dst.SetUint(utmp) case reflect.Float32, reflect.Float64: - if !getFloat64() { + ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits()) + if err != nil { return err } - t.SetFloat(ftmp) + dst.SetFloat(ftmp) case reflect.Bool: value, err := strconv.ParseBool(strings.TrimSpace(string(src))) if err != nil { return err } - t.SetBool(value) + dst.SetBool(value) case reflect.String: - t.SetString(string(src)) + dst.SetString(string(src)) case reflect.Slice: if len(src) == 0 { // non-nil to flag presence src = []byte{} } - t.SetBytes(src) + dst.SetBytes(src) case reflect.Struct: - if t.Type() == timeType { + if dst.Type() == timeType { tv, err := time.Parse(time.RFC3339, string(src)) if err != nil { return err } - t.Set(reflect.ValueOf(tv)) + dst.Set(reflect.ValueOf(tv)) } } return nil diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go index 8df09b3ccee..b45e2f0e61e 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -355,3 +355,47 @@ func TestUnmarshalWithoutNameType(t *testing.T) { t.Fatalf("have %v\nwant %v", x.Attr, OK) } } + +func TestUnmarshalAttr(t *testing.T) { + type ParamVal struct { + Int int `xml:"int,attr"` + } + + type ParamPtr struct { + Int *int `xml:"int,attr"` + } + + type ParamStringPtr struct { + Int *string `xml:"int,attr"` + } + + x := []byte(`<Param int="1" />`) + + p1 := &ParamPtr{} + if err := Unmarshal(x, p1); err != nil { + t.Fatalf("Unmarshal: %s", err) + } + if p1.Int == nil { + t.Fatalf("Unmarshal failed in to *int field") + } else if *p1.Int != 1 { + t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p1.Int, 1) + } + + p2 := &ParamVal{} + if err := Unmarshal(x, p2); err != nil { + t.Fatalf("Unmarshal: %s", err) + } + if p2.Int != 1 { + t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p2.Int, 1) + } + + p3 := &ParamStringPtr{} + if err := Unmarshal(x, p3); err != nil { + t.Fatalf("Unmarshal: %s", err) + } + if p3.Int == nil { + t.Fatalf("Unmarshal failed in to *string field") + } else if *p3.Int != "1" { + t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1) + } +} diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 970d1701932..bbeb28d87ea 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -154,6 +154,9 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro // This will also catch multiple modes in a single field. valid = false } + if finfo.flags&fMode == fAny { + finfo.flags |= fElement + } if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 { valid = false } |