OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [encoding/] [xml/] [marshal.go] - Blame information for rev 750

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2011 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
package xml
6
 
7
import (
8
        "bufio"
9
        "bytes"
10
        "fmt"
11
        "io"
12
        "reflect"
13
        "strconv"
14
        "strings"
15
)
16
 
17
const (
18
        // A generic XML header suitable for use with the output of Marshal.
19
        // This is not automatically added to any output of this package,
20
        // it is provided as a convenience.
21
        Header = `` + "\n"
22
)
23
 
24
// Marshal returns the XML encoding of v.
25
//
26
// Marshal handles an array or slice by marshalling each of the elements.
27
// Marshal handles a pointer by marshalling the value it points at or, if the
28
// pointer is nil, by writing nothing.  Marshal handles an interface value by
29
// marshalling the value it contains or, if the interface value is nil, by
30
// writing nothing.  Marshal handles all other data by writing one or more XML
31
// elements containing the data.
32
//
33
// The name for the XML elements is taken from, in order of preference:
34
//     - the tag on the XMLName field, if the data is a struct
35
//     - the value of the XMLName field of type xml.Name
36
//     - the tag of the struct field used to obtain the data
37
//     - the name of the struct field used to obtain the data
38
//     - the name of the marshalled type
39
//
40
// The XML element for a struct contains marshalled elements for each of the
41
// exported fields of the struct, with these exceptions:
42
//     - the XMLName field, described above, is omitted.
43
//     - a field with tag "-" is omitted.
44
//     - a field with tag "name,attr" becomes an attribute with
45
//       the given name in the XML element.
46
//     - a field with tag ",attr" becomes an attribute with the
47
//       field name in the in the XML element.
48
//     - a field with tag ",chardata" is written as character data,
49
//       not as an XML element.
50
//     - a field with tag ",innerxml" is written verbatim, not subject
51
//       to the usual marshalling procedure.
52
//     - a field with tag ",comment" is written as an XML comment, not
53
//       subject to the usual marshalling procedure. It must not contain
54
//       the "--" string within it.
55
//
56
// If a field uses a tag "a>b>c", then the element c will be nested inside
57
// parent elements a and b.  Fields that appear next to each other that name
58
// the same parent will be enclosed in one XML element.  For example:
59
//
60
//      type Result struct {
61
//              XMLName   xml.Name `xml:"result"`
62
//              Id        int      `xml:"id,attr"`
63
//              FirstName string   `xml:"person>name>first"`
64
//              LastName  string   `xml:"person>name>last"`
65
//              Age       int      `xml:"person>age"`
66
//      }
67
//
68
//      xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42})
69
//
70
// would be marshalled as:
71
//
72
//      
73
//              
74
//                      
75
//                              John
76
//                              Doe
77
//                      
78
//                      42
79
//              
80
//      
81
//
82
// Marshal will return an error if asked to marshal a channel, function, or map.
83
func Marshal(v interface{}) ([]byte, error) {
84
        var b bytes.Buffer
85
        if err := NewEncoder(&b).Encode(v); err != nil {
86
                return nil, err
87
        }
88
        return b.Bytes(), nil
89
}
90
 
91
// An Encoder writes XML data to an output stream.
92
type Encoder struct {
93
        printer
94
}
95
 
96
// NewEncoder returns a new encoder that writes to w.
97
func NewEncoder(w io.Writer) *Encoder {
98
        return &Encoder{printer{bufio.NewWriter(w)}}
99
}
100
 
101
// Encode writes the XML encoding of v to the stream.
102
//
103
// See the documentation for Marshal for details about the conversion
104
// of Go values to XML.
105
func (enc *Encoder) Encode(v interface{}) error {
106
        err := enc.marshalValue(reflect.ValueOf(v), nil)
107
        enc.Flush()
108
        return err
109
}
110
 
111
type printer struct {
112
        *bufio.Writer
113
}
114
 
115
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
116
        if !val.IsValid() {
117
                return nil
118
        }
119
 
120
        kind := val.Kind()
121
        typ := val.Type()
122
 
123
        // Drill into pointers/interfaces
124
        if kind == reflect.Ptr || kind == reflect.Interface {
125
                if val.IsNil() {
126
                        return nil
127
                }
128
                return p.marshalValue(val.Elem(), finfo)
129
        }
130
 
131
        // Slices and arrays iterate over the elements. They do not have an enclosing tag.
132
        if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
133
                for i, n := 0, val.Len(); i < n; i++ {
134
                        if err := p.marshalValue(val.Index(i), finfo); err != nil {
135
                                return err
136
                        }
137
                }
138
                return nil
139
        }
140
 
141
        tinfo, err := getTypeInfo(typ)
142
        if err != nil {
143
                return err
144
        }
145
 
146
        // Precedence for the XML element name is:
147
        // 1. XMLName field in underlying struct;
148
        // 2. field name/tag in the struct field; and
149
        // 3. type name
150
        var xmlns, name string
151
        if tinfo.xmlname != nil {
152
                xmlname := tinfo.xmlname
153
                if xmlname.name != "" {
154
                        xmlns, name = xmlname.xmlns, xmlname.name
155
                } else if v, ok := val.FieldByIndex(xmlname.idx).Interface().(Name); ok && v.Local != "" {
156
                        xmlns, name = v.Space, v.Local
157
                }
158
        }
159
        if name == "" && finfo != nil {
160
                xmlns, name = finfo.xmlns, finfo.name
161
        }
162
        if name == "" {
163
                name = typ.Name()
164
                if name == "" {
165
                        return &UnsupportedTypeError{typ}
166
                }
167
        }
168
 
169
        p.WriteByte('<')
170
        p.WriteString(name)
171
 
172
        if xmlns != "" {
173
                p.WriteString(` xmlns="`)
174
                // TODO: EscapeString, to avoid the allocation.
175
                Escape(p, []byte(xmlns))
176
                p.WriteByte('"')
177
        }
178
 
179
        // Attributes
180
        for i := range tinfo.fields {
181
                finfo := &tinfo.fields[i]
182
                if finfo.flags&fAttr == 0 {
183
                        continue
184
                }
185
                fv := val.FieldByIndex(finfo.idx)
186
                switch fv.Kind() {
187
                case reflect.String, reflect.Array, reflect.Slice:
188
                        // TODO: Should we really do this once ,omitempty is in?
189
                        if fv.Len() == 0 {
190
                                continue
191
                        }
192
                }
193
                p.WriteByte(' ')
194
                p.WriteString(finfo.name)
195
                p.WriteString(`="`)
196
                if err := p.marshalSimple(fv.Type(), fv); err != nil {
197
                        return err
198
                }
199
                p.WriteByte('"')
200
        }
201
        p.WriteByte('>')
202
 
203
        if val.Kind() == reflect.Struct {
204
                err = p.marshalStruct(tinfo, val)
205
        } else {
206
                err = p.marshalSimple(typ, val)
207
        }
208
        if err != nil {
209
                return err
210
        }
211
 
212
        p.WriteByte('<')
213
        p.WriteByte('/')
214
        p.WriteString(name)
215
        p.WriteByte('>')
216
 
217
        return nil
218
}
219
 
220
func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error {
221
        switch val.Kind() {
222
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
223
                p.WriteString(strconv.FormatInt(val.Int(), 10))
224
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
225
                p.WriteString(strconv.FormatUint(val.Uint(), 10))
226
        case reflect.Float32, reflect.Float64:
227
                p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64))
228
        case reflect.String:
229
                // TODO: Add EscapeString.
230
                Escape(p, []byte(val.String()))
231
        case reflect.Bool:
232
                p.WriteString(strconv.FormatBool(val.Bool()))
233
        case reflect.Array:
234
                // will be [...]byte
235
                bytes := make([]byte, val.Len())
236
                for i := range bytes {
237
                        bytes[i] = val.Index(i).Interface().(byte)
238
                }
239
                Escape(p, bytes)
240
        case reflect.Slice:
241
                // will be []byte
242
                Escape(p, val.Bytes())
243
        default:
244
                return &UnsupportedTypeError{typ}
245
        }
246
        return nil
247
}
248
 
249
var ddBytes = []byte("--")
250
 
251
func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
252
        s := parentStack{printer: p}
253
        for i := range tinfo.fields {
254
                finfo := &tinfo.fields[i]
255
                if finfo.flags&(fAttr|fAny) != 0 {
256
                        continue
257
                }
258
                vf := val.FieldByIndex(finfo.idx)
259
                switch finfo.flags & fMode {
260
                case fCharData:
261
                        switch vf.Kind() {
262
                        case reflect.String:
263
                                Escape(p, []byte(vf.String()))
264
                        case reflect.Slice:
265
                                if elem, ok := vf.Interface().([]byte); ok {
266
                                        Escape(p, elem)
267
                                }
268
                        }
269
                        continue
270
 
271
                case fComment:
272
                        k := vf.Kind()
273
                        if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
274
                                return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
275
                        }
276
                        if vf.Len() == 0 {
277
                                continue
278
                        }
279
                        p.WriteString("" is invalid grammar. Make it "- -->"
305
                                p.WriteByte(' ')
306
                        }
307
                        p.WriteString("-->")
308
                        continue
309
 
310
                case fInnerXml:
311
                        iface := vf.Interface()
312
                        switch raw := iface.(type) {
313
                        case []byte:
314
                                p.Write(raw)
315
                                continue
316
                        case string:
317
                                p.WriteString(raw)
318
                                continue
319
                        }
320
 
321
                case fElement:
322
                        s.trim(finfo.parents)
323
                        if len(finfo.parents) > len(s.stack) {
324
                                if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
325
                                        s.push(finfo.parents[len(s.stack):])
326
                                }
327
                        }
328
                }
329
                if err := p.marshalValue(vf, finfo); err != nil {
330
                        return err
331
                }
332
        }
333
        s.trim(nil)
334
        return nil
335
}
336
 
337
type parentStack struct {
338
        *printer
339
        stack []string
340
}
341
 
342
// trim updates the XML context to match the longest common prefix of the stack
343
// and the given parents.  A closing tag will be written for every parent
344
// popped.  Passing a zero slice or nil will close all the elements.
345
func (s *parentStack) trim(parents []string) {
346
        split := 0
347
        for ; split < len(parents) && split < len(s.stack); split++ {
348
                if parents[split] != s.stack[split] {
349
                        break
350
                }
351
        }
352
 
353
        for i := len(s.stack) - 1; i >= split; i-- {
354
                s.WriteString("
355
                s.WriteString(s.stack[i])
356
                s.WriteByte('>')
357
        }
358
 
359
        s.stack = parents[:split]
360
}
361
 
362
// push adds parent elements to the stack and writes open tags.
363
func (s *parentStack) push(parents []string) {
364
        for i := 0; i < len(parents); i++ {
365
                s.WriteString("<")
366
                s.WriteString(parents[i])
367
                s.WriteByte('>')
368
        }
369
        s.stack = append(s.stack, parents...)
370
}
371
 
372
// A MarshalXMLError is returned when Marshal encounters a type
373
// that cannot be converted into XML.
374
type UnsupportedTypeError struct {
375
        Type reflect.Type
376
}
377
 
378
func (e *UnsupportedTypeError) Error() string {
379
        return "xml: unsupported type: " + e.Type.String()
380
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.