~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/xml/read.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-08-03 17:04:59 UTC
  • mfrom: (14.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110803170459-wzd99m3567y80ila
Tags: 1:59-1
* Imported Upstream version 59
* Refresh patches to a new release
* Fix FTBFS on ARM (Closes: #634270)
* Update version.bash to work with Debian packaging and not hg
  repository

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
// For example, given these definitions:
32
32
//
33
33
//      type Email struct {
34
 
//              Where string "attr"
 
34
//              Where string `xml:"attr"`
35
35
//              Addr  string
36
36
//      }
37
37
//
38
38
//      type Result struct {
39
 
//              XMLName xml.Name "result"
 
39
//              XMLName xml.Name `xml:"result"`
40
40
//              Name    string
41
41
//              Phone   string
42
42
//              Email   []Email
43
 
//              Groups  []string "group>value"
 
43
//              Groups  []string `xml:"group>value"`
44
44
//      }
45
45
//
46
46
//      result := Result{Name: "name", Phone: "phone", Email: nil}
79
79
// Groups was assigned considering the element path provided in the
80
80
// field tag.
81
81
//
82
 
// Because Unmarshal uses the reflect package, it can only
83
 
// assign to upper case fields.  Unmarshal uses a case-insensitive
 
82
// Because Unmarshal uses the reflect package, it can only assign
 
83
// to exported (upper case) fields.  Unmarshal uses a case-insensitive
84
84
// comparison to match XML element names to struct field names.
85
85
//
86
 
// Unmarshal maps an XML element to a struct using the following rules:
 
86
// Unmarshal maps an XML element to a struct using the following rules.
 
87
// In the rules, the tag of a field refers to the value associated with the
 
88
// key 'xml' in the struct field's tag (see the example above).
87
89
//
88
90
//   * If the struct has a field of type []byte or string with tag "innerxml",
89
91
//      Unmarshal accumulates the raw XML nested inside the element
92
94
//   * If the struct has a field named XMLName of type xml.Name,
93
95
//      Unmarshal records the element name in that field.
94
96
//
95
 
//   * If the XMLName field has an associated tag string of the form
96
 
//      "tag" or "namespace-URL tag", the XML element must have
97
 
//      the given tag (and, optionally, name space) or else Unmarshal
 
97
//   * If the XMLName field has an associated tag of the form
 
98
//      "name" or "namespace-URL name", the XML element must have
 
99
//      the given name (and, optionally, name space) or else Unmarshal
98
100
//      returns an error.
99
101
//
100
102
//   * If the XML element has an attribute whose name matches a
106
108
//      The struct field may have type []byte or string.
107
109
//      If there is no such field, the character data is discarded.
108
110
//
 
111
//   * If the XML element contains comments, they are accumulated in
 
112
//      the first struct field that has tag "comments".  The struct
 
113
//      field may have type []byte or string.  If there is no such
 
114
//      field, the comments are discarded.
 
115
//
109
116
//   * If the XML element contains a sub-element whose name matches
110
 
//      the prefix of a struct field tag formatted as "a>b>c", unmarshal
 
117
//      the prefix of a tag formatted as "a>b>c", unmarshal
111
118
//      will descend into the XML structure looking for elements with the
112
119
//      given names, and will map the innermost elements to that struct field.
113
 
//      A struct field tag starting with ">" is equivalent to one starting
 
120
//      A tag starting with ">" is equivalent to one starting
114
121
//      with the field name followed by ">".
115
122
//
116
123
//   * If the XML element contains a sub-element whose name
117
 
//      matches a struct field whose tag is neither "attr" nor "chardata",
 
124
//      matches a field whose tag is neither "attr" nor "chardata",
118
125
//      Unmarshal maps the sub-element to that struct field.
119
126
//      Otherwise, if the struct has a field named Any, unmarshal
120
127
//      maps the sub-element to that struct field.
121
128
//
122
129
// Unmarshal maps an XML element to a string or []byte by saving the
123
 
// concatenation of that element's character data in the string or []byte.
124
 
//
125
 
// Unmarshal maps an XML element to a slice by extending the length
126
 
// of the slice and mapping the element to the newly created value.
127
 
//
128
 
// Unmarshal maps an XML element to a bool by setting it to the boolean
129
 
// value represented by the string.
130
 
//
131
 
// Unmarshal maps an XML element to an integer or floating-point
132
 
// field by setting the field to the result of interpreting the string
133
 
// value in decimal.  There is no check for overflow.
 
130
// concatenation of that element's character data in the string or
 
131
// []byte.
 
132
//
 
133
// Unmarshal maps an attribute value to a string or []byte by saving
 
134
// the value in the string or slice.
 
135
//
 
136
// Unmarshal maps an XML element to a slice by extending the length of
 
137
// the slice and mapping the element to the newly created value.
 
138
//
 
139
// Unmarshal maps an XML element or attribute value to a bool by
 
140
// setting it to the boolean value represented by the string.
 
141
//
 
142
// Unmarshal maps an XML element or attribute value to an integer or
 
143
// floating-point field by setting the field to the result of
 
144
// interpreting the string value in decimal.  There is no check for
 
145
// overflow.
134
146
//
135
147
// Unmarshal maps an XML element to an xml.Name by recording the
136
148
// element name.
241
253
 
242
254
        switch v := val; v.Kind() {
243
255
        default:
244
 
                return os.ErrorString("unknown type " + v.Type().String())
 
256
                return os.NewError("unknown type " + v.Type().String())
245
257
 
246
258
        case reflect.Slice:
247
259
                typ := v.Type()
287
299
                // Assign name.
288
300
                if f, ok := typ.FieldByName("XMLName"); ok {
289
301
                        // Validate element name.
290
 
                        if f.Tag != "" {
291
 
                                tag := f.Tag
 
302
                        if tag := f.Tag.Get("xml"); tag != "" {
292
303
                                ns := ""
293
304
                                i := strings.LastIndex(tag, " ")
294
305
                                if i >= 0 {
320
331
                // Also, determine whether we need to save character data or comments.
321
332
                for i, n := 0, typ.NumField(); i < n; i++ {
322
333
                        f := typ.Field(i)
323
 
                        switch f.Tag {
 
334
                        switch f.Tag.Get("xml") {
324
335
                        case "attr":
325
336
                                strv := sv.FieldByIndex(f.Index)
326
 
                                if strv.Kind() != reflect.String {
327
 
                                        return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
328
 
                                }
329
337
                                // Look for attribute.
330
338
                                val := ""
331
339
                                k := strings.ToLower(f.Name)
335
343
                                                break
336
344
                                        }
337
345
                                }
338
 
                                strv.SetString(val)
 
346
                                copyValue(strv, []byte(val))
339
347
 
340
348
                        case "comment":
341
349
                                if !saveComment.IsValid() {
359
367
                                }
360
368
 
361
369
                        default:
362
 
                                if strings.Contains(f.Tag, ">") {
 
370
                                if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") {
363
371
                                        if fieldPaths == nil {
364
372
                                                fieldPaths = make(map[string]pathInfo)
365
373
                                        }
366
 
                                        path := strings.ToLower(f.Tag)
367
 
                                        if strings.HasPrefix(f.Tag, ">") {
 
374
                                        path := strings.ToLower(tag)
 
375
                                        if strings.HasPrefix(tag, ">") {
368
376
                                                path = strings.ToLower(f.Name) + path
369
377
                                        }
370
 
                                        if strings.HasSuffix(f.Tag, ">") {
 
378
                                        if strings.HasSuffix(tag, ">") {
371
379
                                                path = path[:len(path)-1]
372
380
                                        }
373
381
                                        err := addFieldPath(sv, fieldPaths, path, f.Index)
454
462
                }
455
463
        }
456
464
 
457
 
        var err os.Error
 
465
        if err := copyValue(saveData, data); err != nil {
 
466
                return err
 
467
        }
 
468
 
 
469
        switch t := saveComment; t.Kind() {
 
470
        case reflect.String:
 
471
                t.SetString(string(comment))
 
472
        case reflect.Slice:
 
473
                t.Set(reflect.ValueOf(comment))
 
474
        }
 
475
 
 
476
        switch t := saveXML; t.Kind() {
 
477
        case reflect.String:
 
478
                t.SetString(string(saveXMLData))
 
479
        case reflect.Slice:
 
480
                t.Set(reflect.ValueOf(saveXMLData))
 
481
        }
 
482
 
 
483
        return nil
 
484
}
 
485
 
 
486
func copyValue(dst reflect.Value, src []byte) (err os.Error) {
458
487
        // Helper functions for integer and unsigned integer conversions
459
488
        var itmp int64
460
489
        getInt64 := func() bool {
461
 
                itmp, err = strconv.Atoi64(string(data))
 
490
                itmp, err = strconv.Atoi64(string(src))
462
491
                // TODO: should check sizes
463
492
                return err == nil
464
493
        }
465
494
        var utmp uint64
466
495
        getUint64 := func() bool {
467
 
                utmp, err = strconv.Atoui64(string(data))
 
496
                utmp, err = strconv.Atoui64(string(src))
468
497
                // TODO: check for overflow?
469
498
                return err == nil
470
499
        }
471
500
        var ftmp float64
472
501
        getFloat64 := func() bool {
473
 
                ftmp, err = strconv.Atof64(string(data))
 
502
                ftmp, err = strconv.Atof64(string(src))
474
503
                // TODO: check for overflow?
475
504
                return err == nil
476
505
        }
477
506
 
478
507
        // Save accumulated data and comments
479
 
        switch t := saveData; t.Kind() {
 
508
        switch t := dst; t.Kind() {
480
509
        case reflect.Invalid:
481
510
                // Probably a comment, handled below
482
511
        default:
483
 
                return os.ErrorString("cannot happen: unknown type " + t.Type().String())
 
512
                return os.NewError("cannot happen: unknown type " + t.Type().String())
484
513
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
485
514
                if !getInt64() {
486
515
                        return err
497
526
                }
498
527
                t.SetFloat(ftmp)
499
528
        case reflect.Bool:
500
 
                value, err := strconv.Atob(strings.TrimSpace(string(data)))
 
529
                value, err := strconv.Atob(strings.TrimSpace(string(src)))
501
530
                if err != nil {
502
531
                        return err
503
532
                }
504
533
                t.SetBool(value)
505
534
        case reflect.String:
506
 
                t.SetString(string(data))
507
 
        case reflect.Slice:
508
 
                t.Set(reflect.ValueOf(data))
509
 
        }
510
 
 
511
 
        switch t := saveComment; t.Kind() {
512
 
        case reflect.String:
513
 
                t.SetString(string(comment))
514
 
        case reflect.Slice:
515
 
                t.Set(reflect.ValueOf(comment))
516
 
        }
517
 
 
518
 
        switch t := saveXML; t.Kind() {
519
 
        case reflect.String:
520
 
                t.SetString(string(saveXMLData))
521
 
        case reflect.Slice:
522
 
                t.Set(reflect.ValueOf(saveXMLData))
523
 
        }
524
 
 
 
535
                t.SetString(string(src))
 
536
        case reflect.Slice:
 
537
                t.Set(reflect.ValueOf(src))
 
538
        }
525
539
        return nil
526
540
}
527
541
 
561
575
        t := sv.Type()
562
576
        f1 := t.FieldByIndex(idx1)
563
577
        f2 := t.FieldByIndex(idx2)
564
 
        return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
 
578
        return &TagPathError{t, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
565
579
}
566
580
 
567
581
// unmarshalPaths walks down an XML structure looking for