diff options
| author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-02 16:38:43 +0000 |
|---|---|---|
| committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-02 16:38:43 +0000 |
| commit | 2d2d80b8bd963f59534897b3d51ef8bd546cb4bc (patch) | |
| tree | efa0c55763b34cbc633bc494c2743d1b5d9aaff3 /libgo/go/encoding/xml | |
| parent | 2ad2700dbf70b2e49575f3f2307839a45cf2f71c (diff) | |
| download | ppe42-gcc-2d2d80b8bd963f59534897b3d51ef8bd546cb4bc.tar.gz ppe42-gcc-2d2d80b8bd963f59534897b3d51ef8bd546cb4bc.zip | |
libgo: Update to weekly.2012-02-14 release.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184798 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/encoding/xml')
| -rw-r--r-- | libgo/go/encoding/xml/atom_test.go | 13 | ||||
| -rw-r--r-- | libgo/go/encoding/xml/marshal.go | 48 | ||||
| -rw-r--r-- | libgo/go/encoding/xml/marshal_test.go | 93 | ||||
| -rw-r--r-- | libgo/go/encoding/xml/read.go | 13 | ||||
| -rw-r--r-- | libgo/go/encoding/xml/read_test.go | 41 | ||||
| -rw-r--r-- | libgo/go/encoding/xml/typeinfo.go | 17 |
6 files changed, 183 insertions, 42 deletions
diff --git a/libgo/go/encoding/xml/atom_test.go b/libgo/go/encoding/xml/atom_test.go index 8d003aade07..a71284312af 100644 --- a/libgo/go/encoding/xml/atom_test.go +++ b/libgo/go/encoding/xml/atom_test.go @@ -4,6 +4,8 @@ package xml +import "time" + var atomValue = &Feed{ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, Title: "Example Feed", @@ -24,11 +26,10 @@ var atomValue = &Feed{ } var atomXml = `` + - `<feed xmlns="http://www.w3.org/2005/Atom">` + + `<feed xmlns="http://www.w3.org/2005/Atom" updated="2003-12-13T18:30:02Z">` + `<title>Example Feed</title>` + `<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>` + `<link href="http://example.org/"></link>` + - `<updated>2003-12-13T18:30:02Z</updated>` + `<author><name>John Doe</name><uri></uri><email></email></author>` + `<entry>` + `<title>Atom-Powered Robots Run Amok</title>` + @@ -40,8 +41,12 @@ var atomXml = `` + `</entry>` + `</feed>` -func ParseTime(str string) Time { - return Time(str) +func ParseTime(str string) time.Time { + t, err := time.Parse(time.RFC3339, str) + if err != nil { + panic(err) + } + return t } func NewText(text string) Text { diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 7a05a1bb10e..a96c523d553 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -12,6 +12,7 @@ import ( "reflect" "strconv" "strings" + "time" ) const ( @@ -52,6 +53,10 @@ const ( // - a field with tag ",comment" is written as an XML comment, not // subject to the usual marshalling procedure. It must not contain // the "--" string within it. +// - a field with a tag including the "omitempty" option is omitted +// if the field value is empty. The empty values are false, 0, any +// nil pointer or interface value, and any array, slice, map, or +// string of length zero. // // If a field uses a tag "a>b>c", then the element c will be nested inside // parent elements a and b. Fields that appear next to each other that name @@ -63,6 +68,8 @@ const ( // FirstName string `xml:"person>name>first"` // LastName string `xml:"person>name>last"` // Age int `xml:"person>age"` +// Height float `xml:"person>height,omitempty"` +// Married bool `xml:"person>married"` // } // // xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) @@ -76,6 +83,7 @@ const ( // <last>Doe</last> // </name> // <age>42</age> +// <married>false</married> // </person> // </result> // @@ -116,6 +124,9 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { if !val.IsValid() { return nil } + if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) { + return nil + } kind := val.Kind() typ := val.Type() @@ -183,12 +194,8 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { continue } fv := val.FieldByIndex(finfo.idx) - switch fv.Kind() { - case reflect.String, reflect.Array, reflect.Slice: - // TODO: Should we really do this once ,omitempty is in? - if fv.Len() == 0 { - continue - } + if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { + continue } p.WriteByte(' ') p.WriteString(finfo.name) @@ -217,7 +224,14 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { return nil } +var timeType = reflect.TypeOf(time.Time{}) + func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error { + // Normally we don't see structs, but this can happen for an attribute. + if val.Type() == timeType { + p.WriteString(val.Interface().(time.Time).Format(time.RFC3339Nano)) + return nil + } switch val.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p.WriteString(strconv.FormatInt(val.Int(), 10)) @@ -249,6 +263,10 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error { var ddBytes = []byte("--") func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { + if val.Type() == timeType { + p.WriteString(val.Interface().(time.Time).Format(time.RFC3339Nano)) + return nil + } s := parentStack{printer: p} for i := range tinfo.fields { finfo := &tinfo.fields[i] @@ -378,3 +396,21 @@ type UnsupportedTypeError struct { func (e *UnsupportedTypeError) Error() string { return "xml: unsupported type: " + e.Type.String() } + +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +} diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index 0f6c0f0795d..9170fccd243 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" "testing" + "time" ) type DriveType int @@ -38,14 +39,14 @@ type NamedType string type Port struct { XMLName struct{} `xml:"port"` - Type string `xml:"type,attr"` + Type string `xml:"type,attr,omitempty"` Comment string `xml:",comment"` Number string `xml:",chardata"` } type Domain struct { XMLName struct{} `xml:"domain"` - Country string `xml:",attr"` + Country string `xml:",attr,omitempty"` Name []byte `xml:",chardata"` Comment []byte `xml:",comment"` } @@ -149,11 +150,33 @@ type NameInField struct { type AttrTest struct { Int int `xml:",attr"` - Lower int `xml:"int,attr"` + Named int `xml:"int,attr"` Float float64 `xml:",attr"` Uint8 uint8 `xml:",attr"` Bool bool `xml:",attr"` Str string `xml:",attr"` + Bytes []byte `xml:",attr"` +} + +type OmitAttrTest struct { + Int int `xml:",attr,omitempty"` + Named int `xml:"int,attr,omitempty"` + Float float64 `xml:",attr,omitempty"` + Uint8 uint8 `xml:",attr,omitempty"` + Bool bool `xml:",attr,omitempty"` + Str string `xml:",attr,omitempty"` + Bytes []byte `xml:",attr,omitempty"` +} + +type OmitFieldTest struct { + Int int `xml:",omitempty"` + Named int `xml:"int,omitempty"` + Float float64 `xml:",omitempty"` + Uint8 uint8 `xml:",omitempty"` + Bool bool `xml:",omitempty"` + Str string `xml:",omitempty"` + Bytes []byte `xml:",omitempty"` + Ptr *PresenceTest `xml:",omitempty"` } type AnyTest struct { @@ -234,6 +257,12 @@ var marshalTests = []struct { {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, + // Test time. + { + Value: &Plain{time.Unix(1e9, 123456789).UTC()}, + ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`, + }, + // A pointer to struct{} may be used to test for an element's presence. { Value: &PresenceTest{new(struct{})}, @@ -549,13 +578,65 @@ var marshalTests = []struct { { Value: &AttrTest{ Int: 8, - Lower: 9, + Named: 9, + Float: 23.5, + Uint8: 255, + Bool: true, + Str: "str", + Bytes: []byte("byt"), + }, + ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` + + ` Bool="true" Str="str" Bytes="byt"></AttrTest>`, + }, + { + Value: &AttrTest{Bytes: []byte{}}, + ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` + + ` Bool="false" Str="" Bytes=""></AttrTest>`, + }, + { + Value: &OmitAttrTest{ + Int: 8, + Named: 9, + Float: 23.5, + Uint8: 255, + Bool: true, + Str: "str", + Bytes: []byte("byt"), + }, + ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` + + ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`, + }, + { + Value: &OmitAttrTest{}, + ExpectXML: `<OmitAttrTest></OmitAttrTest>`, + }, + + // omitempty on fields + { + Value: &OmitFieldTest{ + Int: 8, + Named: 9, Float: 23.5, Uint8: 255, Bool: true, - Str: "s", + Str: "str", + Bytes: []byte("byt"), + Ptr: &PresenceTest{}, }, - ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="s"></AttrTest>`, + ExpectXML: `<OmitFieldTest>` + + `<Int>8</Int>` + + `<int>9</int>` + + `<Float>23.5</Float>` + + `<Uint8>255</Uint8>` + + `<Bool>true</Bool>` + + `<Str>str</Str>` + + `<Bytes>byt</Bytes>` + + `<Ptr></Ptr>` + + `</OmitFieldTest>`, + }, + { + Value: &OmitFieldTest{}, + ExpectXML: `<OmitFieldTest></OmitFieldTest>`, }, // Test ",any" diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index bde875a0123..b5a3426a328 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -10,6 +10,7 @@ import ( "reflect" "strconv" "strings" + "time" ) // BUG(rsc): Mapping between XML elements and data structures is inherently flawed: @@ -270,6 +271,10 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { v.Set(reflect.ValueOf(start.Name)) break } + if typ == timeType { + saveData = v + break + } sv = v tinfo, err = getTypeInfo(typ) @@ -473,6 +478,14 @@ func copyValue(dst reflect.Value, src []byte) (err error) { src = []byte{} } t.SetBytes(src) + case reflect.Struct: + if t.Type() == timeType { + tv, err := time.Parse(time.RFC3339, string(src)) + if err != nil { + return err + } + t.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 833eafc9a58..8df09b3ccee 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -7,6 +7,7 @@ package xml import ( "reflect" "testing" + "time" ) // Stripped down Atom feed data structures. @@ -24,7 +25,7 @@ func TestUnmarshalFeed(t *testing.T) { // hget http://codereview.appspot.com/rss/mine/rsc const atomFeedString = ` <?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><updated>2009-10-04T01:35:58+00:00</updated><author><name>rietveld<></name></author><entry><title>rietveld: an attempt at pubsubhubbub +<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us" updated="2009-10-04T01:35:58+00:00"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><author><name>rietveld<></name></author><entry><title>rietveld: an attempt at pubsubhubbub </title><link href="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html"> An attempt at adding pubsubhubbub support to Rietveld. http://code.google.com/p/pubsubhubbub @@ -78,26 +79,26 @@ not being used from outside intra_region_diff.py. </summary></entry></feed> ` type Feed struct { - XMLName Name `xml:"http://www.w3.org/2005/Atom feed"` - Title string `xml:"title"` - Id string `xml:"id"` - Link []Link `xml:"link"` - Updated Time `xml:"updated"` - Author Person `xml:"author"` - Entry []Entry `xml:"entry"` + XMLName Name `xml:"http://www.w3.org/2005/Atom feed"` + Title string `xml:"title"` + Id string `xml:"id"` + Link []Link `xml:"link"` + Updated time.Time `xml:"updated,attr"` + Author Person `xml:"author"` + Entry []Entry `xml:"entry"` } type Entry struct { - Title string `xml:"title"` - Id string `xml:"id"` - Link []Link `xml:"link"` - Updated Time `xml:"updated"` - Author Person `xml:"author"` - Summary Text `xml:"summary"` + Title string `xml:"title"` + Id string `xml:"id"` + Link []Link `xml:"link"` + Updated time.Time `xml:"updated"` + Author Person `xml:"author"` + Summary Text `xml:"summary"` } type Link struct { - Rel string `xml:"rel,attr"` + Rel string `xml:"rel,attr,omitempty"` Href string `xml:"href,attr"` } @@ -109,12 +110,10 @@ type Person struct { } type Text struct { - Type string `xml:"type,attr"` + Type string `xml:"type,attr,omitempty"` Body string `xml:",chardata"` } -type Time string - var atomFeed = Feed{ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, Title: "Code Review - My issues", @@ -123,7 +122,7 @@ var atomFeed = Feed{ {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"}, }, Id: "http://codereview.appspot.com/", - Updated: "2009-10-04T01:35:58+00:00", + Updated: ParseTime("2009-10-04T01:35:58+00:00"), Author: Person{ Name: "rietveld<>", InnerXML: "<name>rietveld<></name>", @@ -134,7 +133,7 @@ var atomFeed = Feed{ Link: []Link{ {Rel: "alternate", Href: "http://codereview.appspot.com/126085"}, }, - Updated: "2009-10-04T01:35:58+00:00", + Updated: ParseTime("2009-10-04T01:35:58+00:00"), Author: Person{ Name: "email-address-removed", InnerXML: "<name>email-address-removed</name>", @@ -181,7 +180,7 @@ the top of feeds.py marked NOTE(rsc). Link: []Link{ {Rel: "alternate", Href: "http://codereview.appspot.com/124106"}, }, - Updated: "2009-10-03T23:02:17+00:00", + Updated: ParseTime("2009-10-03T23:02:17+00:00"), Author: Person{ Name: "email-address-removed", InnerXML: "<name>email-address-removed</name>", diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 5475f290d18..8e2e4508b10 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -36,8 +36,7 @@ const ( fComment fAny - // TODO: - //fOmitEmpty + fOmitEmpty fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny ) @@ -133,20 +132,28 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro finfo.flags |= fComment case "any": finfo.flags |= fAny + case "omitempty": + finfo.flags |= fOmitEmpty } } // Validate the flags used. + valid := true switch mode := finfo.flags & fMode; mode { case 0: finfo.flags |= fElement case fAttr, fCharData, fInnerXml, fComment, fAny: - if f.Name != "XMLName" && (tag == "" || mode == fAttr) { - break + if f.Name == "XMLName" || tag != "" && mode != fAttr { + valid = false } - fallthrough default: // This will also catch multiple modes in a single field. + valid = false + } + if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 { + valid = false + } + if !valid { return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q", f.Name, typ, f.Tag.Get("xml")) } |

