Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(473)

Delta Between Two Patch Sets: src/pkg/encoding/xml/read.go

Issue 12751045: code review 12751045: encoding/xml: support generic encoding interfaces (Closed)
Left Patch Set: Created 10 years, 7 months ago
Right Patch Set: diff -r 0a4959c5402a https://code.google.com/p/go/ Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/encoding/xml/marshal.go ('k') | src/pkg/encoding/xml/xml.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package xml 5 package xml
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "encoding"
9 "errors" 10 "errors"
10 "fmt" 11 "fmt"
11 "reflect" 12 "reflect"
12 "strconv" 13 "strconv"
13 "strings" 14 "strings"
14 "time"
15 ) 15 )
16 16
17 // BUG(rsc): Mapping between XML elements and data structures is inherently flaw ed: 17 // BUG(rsc): Mapping between XML elements and data structures is inherently flaw ed:
18 // an XML element is an order-dependent collection of anonymous 18 // an XML element is an order-dependent collection of anonymous
19 // values, while a data structure is an order-independent collection 19 // values, while a data structure is an order-independent collection
20 // of named values. 20 // of named values.
21 // See package json for a textual representation more suitable 21 // See package json for a textual representation more suitable
22 // to data structures. 22 // to data structures.
23 23
24 // Unmarshal parses the XML-encoded data and stores the result in 24 // Unmarshal parses the XML-encoded data and stores the result in
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 171
172 // receiverType returns the receiver type to use in an expression like "%s.Metho dName". 172 // receiverType returns the receiver type to use in an expression like "%s.Metho dName".
173 func receiverType(val interface{}) string { 173 func receiverType(val interface{}) string {
174 t := reflect.TypeOf(val) 174 t := reflect.TypeOf(val)
175 if t.Name() != "" { 175 if t.Name() != "" {
176 return t.String() 176 return t.String()
177 } 177 }
178 return "(" + t.String() + ")" 178 return "(" + t.String() + ")"
179 } 179 }
180 180
181 // unmarshalInterface unmarshals a single XML element into val, 181 // unmarshalInterface unmarshals a single XML element into val.
182 // which is known to implement Unmarshaler.
183 // start is the opening tag of the element. 182 // start is the opening tag of the element.
184 func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { 183 func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
185 // Record that decoder must stop at end tag corresponding to start. 184 // Record that decoder must stop at end tag corresponding to start.
186 p.pushEOF() 185 p.pushEOF()
187 186
188 p.unmarshalDepth++ 187 p.unmarshalDepth++
189 err := val.UnmarshalXML(p, *start) 188 err := val.UnmarshalXML(p, *start)
190 p.unmarshalDepth-- 189 p.unmarshalDepth--
191 if err != nil { 190 if err != nil {
192 p.popEOF() 191 p.popEOF()
193 return err 192 return err
194 } 193 }
195 194
196 if !p.popEOF() { 195 if !p.popEOF() {
197 return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire < %s> element", receiverType(val), start.Name.Local) 196 return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire < %s> element", receiverType(val), start.Name.Local)
198 } 197 }
199 198
200 return nil 199 return nil
201 } 200 }
202 201
202 // unmarshalTextInterface unmarshals a single XML element into val.
203 // The chardata contained in the element (but not its children)
204 // is passed to the text unmarshaler.
205 func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *St artElement) error {
206 var buf []byte
207 depth := 1
208 for depth > 0 {
209 t, err := p.Token()
210 if err != nil {
211 return err
212 }
213 switch t := t.(type) {
214 case CharData:
215 if depth == 1 {
216 buf = append(buf, t...)
217 }
218 case StartElement:
219 depth++
220 case EndElement:
221 depth--
222 }
223 }
224 return val.UnmarshalText(buf)
225 }
226
203 // unmarshalAttr unmarshals a single XML attribute into val. 227 // unmarshalAttr unmarshals a single XML attribute into val.
204 func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { 228 func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
205 if val.Kind() == reflect.Ptr { 229 if val.Kind() == reflect.Ptr {
206 if val.IsNil() { 230 if val.IsNil() {
207 val.Set(reflect.New(val.Type().Elem())) 231 val.Set(reflect.New(val.Type().Elem()))
208 } 232 }
209 val = val.Elem() 233 val = val.Elem()
210 } 234 }
211 235
212 if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) { 236 if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
213 // This is an unmarshaler with a non-pointer receiver, 237 // This is an unmarshaler with a non-pointer receiver,
214 // so it's likely to be incorrect, but we do what we're told. 238 // so it's likely to be incorrect, but we do what we're told.
215 return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) 239 return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
216 } 240 }
217 if val.CanAddr() { 241 if val.CanAddr() {
218 pv := val.Addr() 242 pv := val.Addr()
219 if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType ) { 243 if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType ) {
220 return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr (attr) 244 return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr (attr)
221 } 245 }
222 } 246 }
223 247
224 » // TODO: Check for and use encoding.TextUnmarshaler. 248 » // Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
249 » if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
250 » » // This is an unmarshaler with a non-pointer receiver,
251 » » // so it's likely to be incorrect, but we do what we're told.
252 » » return val.Interface().(encoding.TextUnmarshaler).UnmarshalText( []byte(attr.Value))
253 » }
254 » if val.CanAddr() {
255 » » pv := val.Addr()
256 » » if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType ) {
257 » » » return pv.Interface().(encoding.TextUnmarshaler).Unmarsh alText([]byte(attr.Value))
258 » » }
259 » }
225 260
226 copyValue(val, []byte(attr.Value)) 261 copyValue(val, []byte(attr.Value))
227 return nil 262 return nil
228 } 263 }
229 264
230 var ( 265 var (
231 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() 266 unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
232 unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem() 267 unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem()
268 textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).E lem()
233 ) 269 )
234 270
235 // Unmarshal a single XML element into val. 271 // Unmarshal a single XML element into val.
236 func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { 272 func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
237 // Find start element if we need it. 273 // Find start element if we need it.
238 if start == nil { 274 if start == nil {
239 for { 275 for {
240 tok, err := p.Token() 276 tok, err := p.Token()
241 if err != nil { 277 if err != nil {
242 return err 278 return err
(...skipping 18 matching lines...) Expand all
261 return p.unmarshalInterface(val.Interface().(Unmarshaler), start ) 297 return p.unmarshalInterface(val.Interface().(Unmarshaler), start )
262 } 298 }
263 299
264 if val.CanAddr() { 300 if val.CanAddr() {
265 pv := val.Addr() 301 pv := val.Addr()
266 if pv.CanInterface() && pv.Type().Implements(unmarshalerType) { 302 if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
267 return p.unmarshalInterface(pv.Interface().(Unmarshaler) , start) 303 return p.unmarshalInterface(pv.Interface().(Unmarshaler) , start)
268 } 304 }
269 } 305 }
270 306
271 » // TODO: Check for and use encoding.TextUnmarshaler. 307 » if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
308 » » return p.unmarshalTextInterface(val.Interface().(encoding.TextUn marshaler), start)
309 » }
310
311 » if val.CanAddr() {
312 » » pv := val.Addr()
313 » » if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType ) {
314 » » » return p.unmarshalTextInterface(pv.Interface().(encoding .TextUnmarshaler), start)
315 » » }
316 » }
272 317
273 var ( 318 var (
274 data []byte 319 data []byte
275 saveData reflect.Value 320 saveData reflect.Value
276 comment []byte 321 comment []byte
277 saveComment reflect.Value 322 saveComment reflect.Value
278 saveXML reflect.Value 323 saveXML reflect.Value
279 saveXMLIndex int 324 saveXMLIndex int
280 saveXMLData []byte 325 saveXMLData []byte
281 saveAny reflect.Value 326 saveAny reflect.Value
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 } 368 }
324 return nil 369 return nil
325 370
326 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflec t.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8 , reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Strin g: 371 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflec t.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8 , reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Strin g:
327 saveData = v 372 saveData = v
328 373
329 case reflect.Struct: 374 case reflect.Struct:
330 typ := v.Type() 375 typ := v.Type()
331 if typ == nameType { 376 if typ == nameType {
332 v.Set(reflect.ValueOf(start.Name)) 377 v.Set(reflect.ValueOf(start.Name))
333 break
334 }
335 if typ == timeType {
336 saveData = v
337 break 378 break
338 } 379 }
339 380
340 sv = v 381 sv = v
341 tinfo, err = getTypeInfo(typ) 382 tinfo, err = getTypeInfo(typ)
342 if err != nil { 383 if err != nil {
343 return err 384 return err
344 } 385 }
345 386
346 // Validate and assign element name. 387 // Validate and assign element name.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 data = append(data, t...) 498 data = append(data, t...)
458 } 499 }
459 500
460 case Comment: 501 case Comment:
461 if saveComment.IsValid() { 502 if saveComment.IsValid() {
462 comment = append(comment, t...) 503 comment = append(comment, t...)
463 } 504 }
464 } 505 }
465 } 506 }
466 507
508 if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Impl ements(textUnmarshalerType) {
509 if err := saveData.Interface().(encoding.TextUnmarshaler).Unmars halText(data); err != nil {
510 return err
511 }
512 saveData = reflect.Value{}
513 }
514
515 if saveData.IsValid() && saveData.CanAddr() {
516 pv := saveData.Addr()
517 if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType ) {
518 if err := pv.Interface().(encoding.TextUnmarshaler).Unma rshalText(data); err != nil {
519 return err
520 }
521 saveData = reflect.Value{}
522 }
523 }
524
467 if err := copyValue(saveData, data); err != nil { 525 if err := copyValue(saveData, data); err != nil {
468 return err 526 return err
469 } 527 }
470 528
471 switch t := saveComment; t.Kind() { 529 switch t := saveComment; t.Kind() {
472 case reflect.String: 530 case reflect.String:
473 t.SetString(string(comment)) 531 t.SetString(string(comment))
474 case reflect.Slice: 532 case reflect.Slice:
475 t.Set(reflect.ValueOf(comment)) 533 t.Set(reflect.ValueOf(comment))
476 } 534 }
477 535
478 switch t := saveXML; t.Kind() { 536 switch t := saveXML; t.Kind() {
479 case reflect.String: 537 case reflect.String:
480 t.SetString(string(saveXMLData)) 538 t.SetString(string(saveXMLData))
481 case reflect.Slice: 539 case reflect.Slice:
482 t.Set(reflect.ValueOf(saveXMLData)) 540 t.Set(reflect.ValueOf(saveXMLData))
483 } 541 }
484 542
485 return nil 543 return nil
486 } 544 }
487 545
488 func copyValue(dst reflect.Value, src []byte) (err error) { 546 func copyValue(dst reflect.Value, src []byte) (err error) {
547 dst0 := dst
548
489 if dst.Kind() == reflect.Ptr { 549 if dst.Kind() == reflect.Ptr {
490 if dst.IsNil() { 550 if dst.IsNil() {
491 dst.Set(reflect.New(dst.Type().Elem())) 551 dst.Set(reflect.New(dst.Type().Elem()))
492 } 552 }
493 dst = dst.Elem() 553 dst = dst.Elem()
494 } 554 }
495 555
496 // Save accumulated data. 556 // Save accumulated data.
497 switch dst.Kind() { 557 switch dst.Kind() {
498 case reflect.Invalid: 558 case reflect.Invalid:
499 » » // Probably a commendst. 559 » » // Probably a comment.
500 default: 560 default:
501 » » return errors.New("cannot happen: unknown type " + dst.Type().St ring()) 561 » » return errors.New("cannot unmarshal into " + dst0.Type().String( ))
502 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64: 562 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64:
503 itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits() ) 563 itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits() )
504 if err != nil { 564 if err != nil {
505 return err 565 return err
506 } 566 }
507 dst.SetInt(itmp) 567 dst.SetInt(itmp)
508 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflec t.Uint64, reflect.Uintptr: 568 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflec t.Uint64, reflect.Uintptr:
509 utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits( )) 569 utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits( ))
510 if err != nil { 570 if err != nil {
511 return err 571 return err
(...skipping 12 matching lines...) Expand all
524 } 584 }
525 dst.SetBool(value) 585 dst.SetBool(value)
526 case reflect.String: 586 case reflect.String:
527 dst.SetString(string(src)) 587 dst.SetString(string(src))
528 case reflect.Slice: 588 case reflect.Slice:
529 if len(src) == 0 { 589 if len(src) == 0 {
530 // non-nil to flag presence 590 // non-nil to flag presence
531 src = []byte{} 591 src = []byte{}
532 } 592 }
533 dst.SetBytes(src) 593 dst.SetBytes(src)
534 case reflect.Struct:
535 if dst.Type() == timeType {
536 tv, err := time.Parse(time.RFC3339, string(src))
537 if err != nil {
538 return err
539 }
540 dst.Set(reflect.ValueOf(tv))
541 }
542 } 594 }
543 return nil 595 return nil
544 } 596 }
545 597
546 // unmarshalPath walks down an XML structure looking for wanted 598 // unmarshalPath walks down an XML structure looking for wanted
547 // paths, and calls unmarshal on them. 599 // paths, and calls unmarshal on them.
548 // The consumed result tells whether XML elements have been consumed 600 // The consumed result tells whether XML elements have been consumed
549 // from the Decoder until start's matching end element, or if it's 601 // from the Decoder until start's matching end element, or if it's
550 // still untouched because start is uninteresting for sv's fields. 602 // still untouched because start is uninteresting for sv's fields.
551 func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []str ing, start *StartElement) (consumed bool, err error) { 603 func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []str ing, start *StartElement) (consumed bool, err error) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 switch tok.(type) { 674 switch tok.(type) {
623 case StartElement: 675 case StartElement:
624 if err := d.Skip(); err != nil { 676 if err := d.Skip(); err != nil {
625 return err 677 return err
626 } 678 }
627 case EndElement: 679 case EndElement:
628 return nil 680 return nil
629 } 681 }
630 } 682 }
631 } 683 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b