1
2
3
4
5 package xml
6
7 import (
8 "bufio"
9 "bytes"
10 "encoding"
11 "fmt"
12 "io"
13 "reflect"
14 "strconv"
15 "strings"
16 )
17
18 const (
19
20
21
22 Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
23 )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 func Marshal(v interface{}) ([]byte, error) {
80 var b bytes.Buffer
81 if err := NewEncoder(&b).Encode(v); err != nil {
82 return nil, err
83 }
84 return b.Bytes(), nil
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 type Marshaler interface {
104 MarshalXML(e *Encoder, start StartElement) error
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118 type MarshalerAttr interface {
119 MarshalXMLAttr(name Name) (Attr, error)
120 }
121
122
123
124
125 func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
126 var b bytes.Buffer
127 enc := NewEncoder(&b)
128 enc.Indent(prefix, indent)
129 if err := enc.Encode(v); err != nil {
130 return nil, err
131 }
132 return b.Bytes(), nil
133 }
134
135
136 type Encoder struct {
137 p printer
138 }
139
140
141 func NewEncoder(w io.Writer) *Encoder {
142 e := &Encoder{printer{Writer: bufio.NewWriter(w)}}
143 e.p.encoder = e
144 return e
145 }
146
147
148
149
150 func (enc *Encoder) Indent(prefix, indent string) {
151 enc.p.prefix = prefix
152 enc.p.indent = indent
153 }
154
155
156
157
158
159
160
161 func (enc *Encoder) Encode(v interface{}) error {
162 err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil)
163 if err != nil {
164 return err
165 }
166 return enc.p.Flush()
167 }
168
169
170
171
172
173
174
175
176 func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
177 err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start)
178 if err != nil {
179 return err
180 }
181 return enc.p.Flush()
182 }
183
184 var (
185 begComment = []byte("<!--")
186 endComment = []byte("-->")
187 endProcInst = []byte("?>")
188 )
189
190
191
192
193
194
195
196
197
198
199
200
201
202 func (enc *Encoder) EncodeToken(t Token) error {
203
204 p := &enc.p
205 switch t := t.(type) {
206 case StartElement:
207 if err := p.writeStart(&t); err != nil {
208 return err
209 }
210 case EndElement:
211 if err := p.writeEnd(t.Name); err != nil {
212 return err
213 }
214 case CharData:
215 escapeText(p, t, false)
216 case Comment:
217 if bytes.Contains(t, endComment) {
218 return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
219 }
220 p.WriteString("<!--")
221 p.Write(t)
222 p.WriteString("-->")
223 return p.cachedWriteError()
224 case ProcInst:
225
226
227 if t.Target == "xml" && p.Buffered() != 0 {
228 return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
229 }
230 if !isNameString(t.Target) {
231 return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
232 }
233 if bytes.Contains(t.Inst, endProcInst) {
234 return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
235 }
236 p.WriteString("<?")
237 p.WriteString(t.Target)
238 if len(t.Inst) > 0 {
239 p.WriteByte(' ')
240 p.Write(t.Inst)
241 }
242 p.WriteString("?>")
243 case Directive:
244 if !isValidDirective(t) {
245 return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
246 }
247 p.WriteString("<!")
248 p.Write(t)
249 p.WriteString(">")
250 default:
251 return fmt.Errorf("xml: EncodeToken of invalid token type")
252
253 }
254 return p.cachedWriteError()
255 }
256
257
258
259 func isValidDirective(dir Directive) bool {
260 var (
261 depth int
262 inquote uint8
263 incomment bool
264 )
265 for i, c := range dir {
266 switch {
267 case incomment:
268 if c == '>' {
269 if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
270 incomment = false
271 }
272 }
273
274 case inquote != 0:
275 if c == inquote {
276 inquote = 0
277 }
278
279 case c == '\'' || c == '"':
280 inquote = c
281 case c == '<':
282 if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
283 incomment = true
284 } else {
285 depth++
286 }
287 case c == '>':
288 if depth == 0 {
289 return false
290 }
291 depth--
292 }
293 }
294 return depth == 0 && inquote == 0 && !incomment
295 }
296
297
298
299 func (enc *Encoder) Flush() error {
300 return enc.p.Flush()
301 }
302
303 type printer struct {
304 *bufio.Writer
305 encoder *Encoder
306 seq int
307 indent string
308 prefix string
309 depth int
310 indentedIn bool
311 putNewline bool
312 attrNS map[string]string
313 attrPrefix map[string]string
314 prefixes []string
315 tags []Name
316 }
317
318
319
320 func (p *printer) createAttrPrefix(url string) string {
321 if prefix := p.attrPrefix[url]; prefix != "" {
322 return prefix
323 }
324
325
326
327
328
329 if url == xmlURL {
330 return xmlPrefix
331 }
332
333
334 if p.attrPrefix == nil {
335 p.attrPrefix = make(map[string]string)
336 p.attrNS = make(map[string]string)
337 }
338
339
340
341 prefix := strings.TrimRight(url, "/")
342 if i := strings.LastIndex(prefix, "/"); i >= 0 {
343 prefix = prefix[i+1:]
344 }
345 if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
346 prefix = "_"
347 }
348
349
350
351
352 if len(prefix) >= 3 && strings.EqualFold(prefix[:3], "xml") {
353 prefix = "_" + prefix
354 }
355 if p.attrNS[prefix] != "" {
356
357 for p.seq++; ; p.seq++ {
358 if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
359 prefix = id
360 break
361 }
362 }
363 }
364
365 p.attrPrefix[url] = prefix
366 p.attrNS[prefix] = url
367
368 p.WriteString(`xmlns:`)
369 p.WriteString(prefix)
370 p.WriteString(`="`)
371 EscapeText(p, []byte(url))
372 p.WriteString(`" `)
373
374 p.prefixes = append(p.prefixes, prefix)
375
376 return prefix
377 }
378
379
380 func (p *printer) deleteAttrPrefix(prefix string) {
381 delete(p.attrPrefix, p.attrNS[prefix])
382 delete(p.attrNS, prefix)
383 }
384
385 func (p *printer) markPrefix() {
386 p.prefixes = append(p.prefixes, "")
387 }
388
389 func (p *printer) popPrefix() {
390 for len(p.prefixes) > 0 {
391 prefix := p.prefixes[len(p.prefixes)-1]
392 p.prefixes = p.prefixes[:len(p.prefixes)-1]
393 if prefix == "" {
394 break
395 }
396 p.deleteAttrPrefix(prefix)
397 }
398 }
399
400 var (
401 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
402 marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem()
403 textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
404 )
405
406
407
408 func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
409 if startTemplate != nil && startTemplate.Name.Local == "" {
410 return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
411 }
412
413 if !val.IsValid() {
414 return nil
415 }
416 if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
417 return nil
418 }
419
420
421
422
423 for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
424 if val.IsNil() {
425 return nil
426 }
427 val = val.Elem()
428 }
429
430 kind := val.Kind()
431 typ := val.Type()
432
433
434 if val.CanInterface() && typ.Implements(marshalerType) {
435 return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
436 }
437 if val.CanAddr() {
438 pv := val.Addr()
439 if pv.CanInterface() && pv.Type().Implements(marshalerType) {
440 return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
441 }
442 }
443
444
445 if val.CanInterface() && typ.Implements(textMarshalerType) {
446 return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
447 }
448 if val.CanAddr() {
449 pv := val.Addr()
450 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
451 return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
452 }
453 }
454
455
456 if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
457 for i, n := 0, val.Len(); i < n; i++ {
458 if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
459 return err
460 }
461 }
462 return nil
463 }
464
465 tinfo, err := getTypeInfo(typ)
466 if err != nil {
467 return err
468 }
469
470
471
472
473
474
475
476 var start StartElement
477
478 if startTemplate != nil {
479 start.Name = startTemplate.Name
480 start.Attr = append(start.Attr, startTemplate.Attr...)
481 } else if tinfo.xmlname != nil {
482 xmlname := tinfo.xmlname
483 if xmlname.name != "" {
484 start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
485 } else {
486 fv := xmlname.value(val, dontInitNilPointers)
487 if v, ok := fv.Interface().(Name); ok && v.Local != "" {
488 start.Name = v
489 }
490 }
491 }
492 if start.Name.Local == "" && finfo != nil {
493 start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
494 }
495 if start.Name.Local == "" {
496 name := typ.Name()
497 if name == "" {
498 return &UnsupportedTypeError{typ}
499 }
500 start.Name.Local = name
501 }
502
503
504 for i := range tinfo.fields {
505 finfo := &tinfo.fields[i]
506 if finfo.flags&fAttr == 0 {
507 continue
508 }
509 fv := finfo.value(val, dontInitNilPointers)
510
511 if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
512 continue
513 }
514
515 if fv.Kind() == reflect.Interface && fv.IsNil() {
516 continue
517 }
518
519 name := Name{Space: finfo.xmlns, Local: finfo.name}
520 if err := p.marshalAttr(&start, name, fv); err != nil {
521 return err
522 }
523 }
524
525 if err := p.writeStart(&start); err != nil {
526 return err
527 }
528
529 if val.Kind() == reflect.Struct {
530 err = p.marshalStruct(tinfo, val)
531 } else {
532 s, b, err1 := p.marshalSimple(typ, val)
533 if err1 != nil {
534 err = err1
535 } else if b != nil {
536 EscapeText(p, b)
537 } else {
538 p.EscapeString(s)
539 }
540 }
541 if err != nil {
542 return err
543 }
544
545 if err := p.writeEnd(start.Name); err != nil {
546 return err
547 }
548
549 return p.cachedWriteError()
550 }
551
552
553 func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
554 if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
555 attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
556 if err != nil {
557 return err
558 }
559 if attr.Name.Local != "" {
560 start.Attr = append(start.Attr, attr)
561 }
562 return nil
563 }
564
565 if val.CanAddr() {
566 pv := val.Addr()
567 if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
568 attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
569 if err != nil {
570 return err
571 }
572 if attr.Name.Local != "" {
573 start.Attr = append(start.Attr, attr)
574 }
575 return nil
576 }
577 }
578
579 if val.CanInterface() && val.Type().Implements(textMarshalerType) {
580 text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
581 if err != nil {
582 return err
583 }
584 start.Attr = append(start.Attr, Attr{name, string(text)})
585 return nil
586 }
587
588 if val.CanAddr() {
589 pv := val.Addr()
590 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
591 text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
592 if err != nil {
593 return err
594 }
595 start.Attr = append(start.Attr, Attr{name, string(text)})
596 return nil
597 }
598 }
599
600
601 switch val.Kind() {
602 case reflect.Ptr, reflect.Interface:
603 if val.IsNil() {
604 return nil
605 }
606 val = val.Elem()
607 }
608
609
610 if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
611 n := val.Len()
612 for i := 0; i < n; i++ {
613 if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
614 return err
615 }
616 }
617 return nil
618 }
619
620 if val.Type() == attrType {
621 start.Attr = append(start.Attr, val.Interface().(Attr))
622 return nil
623 }
624
625 s, b, err := p.marshalSimple(val.Type(), val)
626 if err != nil {
627 return err
628 }
629 if b != nil {
630 s = string(b)
631 }
632 start.Attr = append(start.Attr, Attr{name, s})
633 return nil
634 }
635
636
637
638 func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
639 var start StartElement
640
641
642 if startTemplate != nil {
643 start.Name = startTemplate.Name
644 start.Attr = append(start.Attr, startTemplate.Attr...)
645 } else if finfo != nil && finfo.name != "" {
646 start.Name.Local = finfo.name
647 start.Name.Space = finfo.xmlns
648 } else if typ.Name() != "" {
649 start.Name.Local = typ.Name()
650 } else {
651
652
653 start.Name.Local = typ.Elem().Name()
654 }
655 return start
656 }
657
658
659 func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
660
661
662 p.tags = append(p.tags, Name{})
663 n := len(p.tags)
664
665 err := val.MarshalXML(p.encoder, start)
666 if err != nil {
667 return err
668 }
669
670
671 if len(p.tags) > n {
672 return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
673 }
674 p.tags = p.tags[:n-1]
675 return nil
676 }
677
678
679 func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
680 if err := p.writeStart(&start); err != nil {
681 return err
682 }
683 text, err := val.MarshalText()
684 if err != nil {
685 return err
686 }
687 EscapeText(p, text)
688 return p.writeEnd(start.Name)
689 }
690
691
692 func (p *printer) writeStart(start *StartElement) error {
693 if start.Name.Local == "" {
694 return fmt.Errorf("xml: start tag with no name")
695 }
696
697 p.tags = append(p.tags, start.Name)
698 p.markPrefix()
699
700 p.writeIndent(1)
701 p.WriteByte('<')
702 p.WriteString(start.Name.Local)
703
704 if start.Name.Space != "" {
705 p.WriteString(` xmlns="`)
706 p.EscapeString(start.Name.Space)
707 p.WriteByte('"')
708 }
709
710
711 for _, attr := range start.Attr {
712 name := attr.Name
713 if name.Local == "" {
714 continue
715 }
716 p.WriteByte(' ')
717 if name.Space != "" {
718 p.WriteString(p.createAttrPrefix(name.Space))
719 p.WriteByte(':')
720 }
721 p.WriteString(name.Local)
722 p.WriteString(`="`)
723 p.EscapeString(attr.Value)
724 p.WriteByte('"')
725 }
726 p.WriteByte('>')
727 return nil
728 }
729
730 func (p *printer) writeEnd(name Name) error {
731 if name.Local == "" {
732 return fmt.Errorf("xml: end tag with no name")
733 }
734 if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
735 return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
736 }
737 if top := p.tags[len(p.tags)-1]; top != name {
738 if top.Local != name.Local {
739 return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
740 }
741 return fmt.Errorf("xml: end tag </%s> in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space)
742 }
743 p.tags = p.tags[:len(p.tags)-1]
744
745 p.writeIndent(-1)
746 p.WriteByte('<')
747 p.WriteByte('/')
748 p.WriteString(name.Local)
749 p.WriteByte('>')
750 p.popPrefix()
751 return nil
752 }
753
754 func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
755 switch val.Kind() {
756 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
757 return strconv.FormatInt(val.Int(), 10), nil, nil
758 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
759 return strconv.FormatUint(val.Uint(), 10), nil, nil
760 case reflect.Float32, reflect.Float64:
761 return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
762 case reflect.String:
763 return val.String(), nil, nil
764 case reflect.Bool:
765 return strconv.FormatBool(val.Bool()), nil, nil
766 case reflect.Array:
767 if typ.Elem().Kind() != reflect.Uint8 {
768 break
769 }
770
771 var bytes []byte
772 if val.CanAddr() {
773 bytes = val.Slice(0, val.Len()).Bytes()
774 } else {
775 bytes = make([]byte, val.Len())
776 reflect.Copy(reflect.ValueOf(bytes), val)
777 }
778 return "", bytes, nil
779 case reflect.Slice:
780 if typ.Elem().Kind() != reflect.Uint8 {
781 break
782 }
783
784 return "", val.Bytes(), nil
785 }
786 return "", nil, &UnsupportedTypeError{typ}
787 }
788
789 var ddBytes = []byte("--")
790
791
792
793
794
795 func indirect(vf reflect.Value) reflect.Value {
796 for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
797 if vf.IsNil() {
798 return vf
799 }
800 vf = vf.Elem()
801 }
802 return vf
803 }
804
805 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
806 s := parentStack{p: p}
807 for i := range tinfo.fields {
808 finfo := &tinfo.fields[i]
809 if finfo.flags&fAttr != 0 {
810 continue
811 }
812 vf := finfo.value(val, dontInitNilPointers)
813 if !vf.IsValid() {
814
815
816 continue
817 }
818
819 switch finfo.flags & fMode {
820 case fCDATA, fCharData:
821 emit := EscapeText
822 if finfo.flags&fMode == fCDATA {
823 emit = emitCDATA
824 }
825 if err := s.trim(finfo.parents); err != nil {
826 return err
827 }
828 if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
829 data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
830 if err != nil {
831 return err
832 }
833 if err := emit(p, data); err != nil {
834 return err
835 }
836 continue
837 }
838 if vf.CanAddr() {
839 pv := vf.Addr()
840 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
841 data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
842 if err != nil {
843 return err
844 }
845 if err := emit(p, data); err != nil {
846 return err
847 }
848 continue
849 }
850 }
851
852 var scratch [64]byte
853 vf = indirect(vf)
854 switch vf.Kind() {
855 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
856 if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
857 return err
858 }
859 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
860 if err := emit(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)); err != nil {
861 return err
862 }
863 case reflect.Float32, reflect.Float64:
864 if err := emit(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())); err != nil {
865 return err
866 }
867 case reflect.Bool:
868 if err := emit(p, strconv.AppendBool(scratch[:0], vf.Bool())); err != nil {
869 return err
870 }
871 case reflect.String:
872 if err := emit(p, []byte(vf.String())); err != nil {
873 return err
874 }
875 case reflect.Slice:
876 if elem, ok := vf.Interface().([]byte); ok {
877 if err := emit(p, elem); err != nil {
878 return err
879 }
880 }
881 }
882 continue
883
884 case fComment:
885 if err := s.trim(finfo.parents); err != nil {
886 return err
887 }
888 vf = indirect(vf)
889 k := vf.Kind()
890 if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
891 return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
892 }
893 if vf.Len() == 0 {
894 continue
895 }
896 p.writeIndent(0)
897 p.WriteString("<!--")
898 dashDash := false
899 dashLast := false
900 switch k {
901 case reflect.String:
902 s := vf.String()
903 dashDash = strings.Contains(s, "--")
904 dashLast = s[len(s)-1] == '-'
905 if !dashDash {
906 p.WriteString(s)
907 }
908 case reflect.Slice:
909 b := vf.Bytes()
910 dashDash = bytes.Contains(b, ddBytes)
911 dashLast = b[len(b)-1] == '-'
912 if !dashDash {
913 p.Write(b)
914 }
915 default:
916 panic("can't happen")
917 }
918 if dashDash {
919 return fmt.Errorf(`xml: comments must not contain "--"`)
920 }
921 if dashLast {
922
923 p.WriteByte(' ')
924 }
925 p.WriteString("-->")
926 continue
927
928 case fInnerXML:
929 vf = indirect(vf)
930 iface := vf.Interface()
931 switch raw := iface.(type) {
932 case []byte:
933 p.Write(raw)
934 continue
935 case string:
936 p.WriteString(raw)
937 continue
938 }
939
940 case fElement, fElement | fAny:
941 if err := s.trim(finfo.parents); err != nil {
942 return err
943 }
944 if len(finfo.parents) > len(s.stack) {
945 if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
946 if err := s.push(finfo.parents[len(s.stack):]); err != nil {
947 return err
948 }
949 }
950 }
951 }
952 if err := p.marshalValue(vf, finfo, nil); err != nil {
953 return err
954 }
955 }
956 s.trim(nil)
957 return p.cachedWriteError()
958 }
959
960
961 func (p *printer) cachedWriteError() error {
962 _, err := p.Write(nil)
963 return err
964 }
965
966 func (p *printer) writeIndent(depthDelta int) {
967 if len(p.prefix) == 0 && len(p.indent) == 0 {
968 return
969 }
970 if depthDelta < 0 {
971 p.depth--
972 if p.indentedIn {
973 p.indentedIn = false
974 return
975 }
976 p.indentedIn = false
977 }
978 if p.putNewline {
979 p.WriteByte('\n')
980 } else {
981 p.putNewline = true
982 }
983 if len(p.prefix) > 0 {
984 p.WriteString(p.prefix)
985 }
986 if len(p.indent) > 0 {
987 for i := 0; i < p.depth; i++ {
988 p.WriteString(p.indent)
989 }
990 }
991 if depthDelta > 0 {
992 p.depth++
993 p.indentedIn = true
994 }
995 }
996
997 type parentStack struct {
998 p *printer
999 stack []string
1000 }
1001
1002
1003
1004
1005 func (s *parentStack) trim(parents []string) error {
1006 split := 0
1007 for ; split < len(parents) && split < len(s.stack); split++ {
1008 if parents[split] != s.stack[split] {
1009 break
1010 }
1011 }
1012 for i := len(s.stack) - 1; i >= split; i-- {
1013 if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
1014 return err
1015 }
1016 }
1017 s.stack = s.stack[:split]
1018 return nil
1019 }
1020
1021
1022 func (s *parentStack) push(parents []string) error {
1023 for i := 0; i < len(parents); i++ {
1024 if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
1025 return err
1026 }
1027 }
1028 s.stack = append(s.stack, parents...)
1029 return nil
1030 }
1031
1032
1033
1034 type UnsupportedTypeError struct {
1035 Type reflect.Type
1036 }
1037
1038 func (e *UnsupportedTypeError) Error() string {
1039 return "xml: unsupported type: " + e.Type.String()
1040 }
1041
1042 func isEmptyValue(v reflect.Value) bool {
1043 switch v.Kind() {
1044 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
1045 return v.Len() == 0
1046 case reflect.Bool:
1047 return !v.Bool()
1048 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1049 return v.Int() == 0
1050 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1051 return v.Uint() == 0
1052 case reflect.Float32, reflect.Float64:
1053 return v.Float() == 0
1054 case reflect.Interface, reflect.Ptr:
1055 return v.IsNil()
1056 }
1057 return false
1058 }
1059
View as plain text