LEFT | RIGHT |
(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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
LEFT | RIGHT |