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 any) ([]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 any, 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 any) 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 any, 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.Pointer {
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 i := strings.IndexByte(name, '['); i >= 0 {
498
499 name = name[:i]
500 }
501 if name == "" {
502 return &UnsupportedTypeError{typ}
503 }
504 start.Name.Local = name
505 }
506
507
508 for i := range tinfo.fields {
509 finfo := &tinfo.fields[i]
510 if finfo.flags&fAttr == 0 {
511 continue
512 }
513 fv := finfo.value(val, dontInitNilPointers)
514
515 if finfo.flags&fOmitEmpty != 0 && (!fv.IsValid() || isEmptyValue(fv)) {
516 continue
517 }
518
519 if fv.Kind() == reflect.Interface && fv.IsNil() {
520 continue
521 }
522
523 name := Name{Space: finfo.xmlns, Local: finfo.name}
524 if err := p.marshalAttr(&start, name, fv); err != nil {
525 return err
526 }
527 }
528
529 if err := p.writeStart(&start); err != nil {
530 return err
531 }
532
533 if val.Kind() == reflect.Struct {
534 err = p.marshalStruct(tinfo, val)
535 } else {
536 s, b, err1 := p.marshalSimple(typ, val)
537 if err1 != nil {
538 err = err1
539 } else if b != nil {
540 EscapeText(p, b)
541 } else {
542 p.EscapeString(s)
543 }
544 }
545 if err != nil {
546 return err
547 }
548
549 if err := p.writeEnd(start.Name); err != nil {
550 return err
551 }
552
553 return p.cachedWriteError()
554 }
555
556
557 func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
558 if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
559 attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
560 if err != nil {
561 return err
562 }
563 if attr.Name.Local != "" {
564 start.Attr = append(start.Attr, attr)
565 }
566 return nil
567 }
568
569 if val.CanAddr() {
570 pv := val.Addr()
571 if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
572 attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
573 if err != nil {
574 return err
575 }
576 if attr.Name.Local != "" {
577 start.Attr = append(start.Attr, attr)
578 }
579 return nil
580 }
581 }
582
583 if val.CanInterface() && val.Type().Implements(textMarshalerType) {
584 text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
585 if err != nil {
586 return err
587 }
588 start.Attr = append(start.Attr, Attr{name, string(text)})
589 return nil
590 }
591
592 if val.CanAddr() {
593 pv := val.Addr()
594 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
595 text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
596 if err != nil {
597 return err
598 }
599 start.Attr = append(start.Attr, Attr{name, string(text)})
600 return nil
601 }
602 }
603
604
605 switch val.Kind() {
606 case reflect.Pointer, reflect.Interface:
607 if val.IsNil() {
608 return nil
609 }
610 val = val.Elem()
611 }
612
613
614 if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
615 n := val.Len()
616 for i := 0; i < n; i++ {
617 if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
618 return err
619 }
620 }
621 return nil
622 }
623
624 if val.Type() == attrType {
625 start.Attr = append(start.Attr, val.Interface().(Attr))
626 return nil
627 }
628
629 s, b, err := p.marshalSimple(val.Type(), val)
630 if err != nil {
631 return err
632 }
633 if b != nil {
634 s = string(b)
635 }
636 start.Attr = append(start.Attr, Attr{name, s})
637 return nil
638 }
639
640
641
642 func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
643 var start StartElement
644
645
646 if startTemplate != nil {
647 start.Name = startTemplate.Name
648 start.Attr = append(start.Attr, startTemplate.Attr...)
649 } else if finfo != nil && finfo.name != "" {
650 start.Name.Local = finfo.name
651 start.Name.Space = finfo.xmlns
652 } else if typ.Name() != "" {
653 start.Name.Local = typ.Name()
654 } else {
655
656
657 start.Name.Local = typ.Elem().Name()
658 }
659 return start
660 }
661
662
663 func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
664
665
666 p.tags = append(p.tags, Name{})
667 n := len(p.tags)
668
669 err := val.MarshalXML(p.encoder, start)
670 if err != nil {
671 return err
672 }
673
674
675 if len(p.tags) > n {
676 return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
677 }
678 p.tags = p.tags[:n-1]
679 return nil
680 }
681
682
683 func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
684 if err := p.writeStart(&start); err != nil {
685 return err
686 }
687 text, err := val.MarshalText()
688 if err != nil {
689 return err
690 }
691 EscapeText(p, text)
692 return p.writeEnd(start.Name)
693 }
694
695
696 func (p *printer) writeStart(start *StartElement) error {
697 if start.Name.Local == "" {
698 return fmt.Errorf("xml: start tag with no name")
699 }
700
701 p.tags = append(p.tags, start.Name)
702 p.markPrefix()
703
704 p.writeIndent(1)
705 p.WriteByte('<')
706 p.WriteString(start.Name.Local)
707
708 if start.Name.Space != "" {
709 p.WriteString(` xmlns="`)
710 p.EscapeString(start.Name.Space)
711 p.WriteByte('"')
712 }
713
714
715 for _, attr := range start.Attr {
716 name := attr.Name
717 if name.Local == "" {
718 continue
719 }
720 p.WriteByte(' ')
721 if name.Space != "" {
722 p.WriteString(p.createAttrPrefix(name.Space))
723 p.WriteByte(':')
724 }
725 p.WriteString(name.Local)
726 p.WriteString(`="`)
727 p.EscapeString(attr.Value)
728 p.WriteByte('"')
729 }
730 p.WriteByte('>')
731 return nil
732 }
733
734 func (p *printer) writeEnd(name Name) error {
735 if name.Local == "" {
736 return fmt.Errorf("xml: end tag with no name")
737 }
738 if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
739 return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
740 }
741 if top := p.tags[len(p.tags)-1]; top != name {
742 if top.Local != name.Local {
743 return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
744 }
745 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)
746 }
747 p.tags = p.tags[:len(p.tags)-1]
748
749 p.writeIndent(-1)
750 p.WriteByte('<')
751 p.WriteByte('/')
752 p.WriteString(name.Local)
753 p.WriteByte('>')
754 p.popPrefix()
755 return nil
756 }
757
758 func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
759 switch val.Kind() {
760 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
761 return strconv.FormatInt(val.Int(), 10), nil, nil
762 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
763 return strconv.FormatUint(val.Uint(), 10), nil, nil
764 case reflect.Float32, reflect.Float64:
765 return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
766 case reflect.String:
767 return val.String(), nil, nil
768 case reflect.Bool:
769 return strconv.FormatBool(val.Bool()), nil, nil
770 case reflect.Array:
771 if typ.Elem().Kind() != reflect.Uint8 {
772 break
773 }
774
775 var bytes []byte
776 if val.CanAddr() {
777 bytes = val.Slice(0, val.Len()).Bytes()
778 } else {
779 bytes = make([]byte, val.Len())
780 reflect.Copy(reflect.ValueOf(bytes), val)
781 }
782 return "", bytes, nil
783 case reflect.Slice:
784 if typ.Elem().Kind() != reflect.Uint8 {
785 break
786 }
787
788 return "", val.Bytes(), nil
789 }
790 return "", nil, &UnsupportedTypeError{typ}
791 }
792
793 var ddBytes = []byte("--")
794
795
796
797
798
799 func indirect(vf reflect.Value) reflect.Value {
800 for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Pointer {
801 if vf.IsNil() {
802 return vf
803 }
804 vf = vf.Elem()
805 }
806 return vf
807 }
808
809 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
810 s := parentStack{p: p}
811 for i := range tinfo.fields {
812 finfo := &tinfo.fields[i]
813 if finfo.flags&fAttr != 0 {
814 continue
815 }
816 vf := finfo.value(val, dontInitNilPointers)
817 if !vf.IsValid() {
818
819
820 continue
821 }
822
823 switch finfo.flags & fMode {
824 case fCDATA, fCharData:
825 emit := EscapeText
826 if finfo.flags&fMode == fCDATA {
827 emit = emitCDATA
828 }
829 if err := s.trim(finfo.parents); err != nil {
830 return err
831 }
832 if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
833 data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
834 if err != nil {
835 return err
836 }
837 if err := emit(p, data); err != nil {
838 return err
839 }
840 continue
841 }
842 if vf.CanAddr() {
843 pv := vf.Addr()
844 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
845 data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
846 if err != nil {
847 return err
848 }
849 if err := emit(p, data); err != nil {
850 return err
851 }
852 continue
853 }
854 }
855
856 var scratch [64]byte
857 vf = indirect(vf)
858 switch vf.Kind() {
859 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
860 if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
861 return err
862 }
863 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
864 if err := emit(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)); err != nil {
865 return err
866 }
867 case reflect.Float32, reflect.Float64:
868 if err := emit(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())); err != nil {
869 return err
870 }
871 case reflect.Bool:
872 if err := emit(p, strconv.AppendBool(scratch[:0], vf.Bool())); err != nil {
873 return err
874 }
875 case reflect.String:
876 if err := emit(p, []byte(vf.String())); err != nil {
877 return err
878 }
879 case reflect.Slice:
880 if elem, ok := vf.Interface().([]byte); ok {
881 if err := emit(p, elem); err != nil {
882 return err
883 }
884 }
885 }
886 continue
887
888 case fComment:
889 if err := s.trim(finfo.parents); err != nil {
890 return err
891 }
892 vf = indirect(vf)
893 k := vf.Kind()
894 if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
895 return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
896 }
897 if vf.Len() == 0 {
898 continue
899 }
900 p.writeIndent(0)
901 p.WriteString("<!--")
902 dashDash := false
903 dashLast := false
904 switch k {
905 case reflect.String:
906 s := vf.String()
907 dashDash = strings.Contains(s, "--")
908 dashLast = s[len(s)-1] == '-'
909 if !dashDash {
910 p.WriteString(s)
911 }
912 case reflect.Slice:
913 b := vf.Bytes()
914 dashDash = bytes.Contains(b, ddBytes)
915 dashLast = b[len(b)-1] == '-'
916 if !dashDash {
917 p.Write(b)
918 }
919 default:
920 panic("can't happen")
921 }
922 if dashDash {
923 return fmt.Errorf(`xml: comments must not contain "--"`)
924 }
925 if dashLast {
926
927 p.WriteByte(' ')
928 }
929 p.WriteString("-->")
930 continue
931
932 case fInnerXML:
933 vf = indirect(vf)
934 iface := vf.Interface()
935 switch raw := iface.(type) {
936 case []byte:
937 p.Write(raw)
938 continue
939 case string:
940 p.WriteString(raw)
941 continue
942 }
943
944 case fElement, fElement | fAny:
945 if err := s.trim(finfo.parents); err != nil {
946 return err
947 }
948 if len(finfo.parents) > len(s.stack) {
949 if vf.Kind() != reflect.Pointer && vf.Kind() != reflect.Interface || !vf.IsNil() {
950 if err := s.push(finfo.parents[len(s.stack):]); err != nil {
951 return err
952 }
953 }
954 }
955 }
956 if err := p.marshalValue(vf, finfo, nil); err != nil {
957 return err
958 }
959 }
960 s.trim(nil)
961 return p.cachedWriteError()
962 }
963
964
965 func (p *printer) cachedWriteError() error {
966 _, err := p.Write(nil)
967 return err
968 }
969
970 func (p *printer) writeIndent(depthDelta int) {
971 if len(p.prefix) == 0 && len(p.indent) == 0 {
972 return
973 }
974 if depthDelta < 0 {
975 p.depth--
976 if p.indentedIn {
977 p.indentedIn = false
978 return
979 }
980 p.indentedIn = false
981 }
982 if p.putNewline {
983 p.WriteByte('\n')
984 } else {
985 p.putNewline = true
986 }
987 if len(p.prefix) > 0 {
988 p.WriteString(p.prefix)
989 }
990 if len(p.indent) > 0 {
991 for i := 0; i < p.depth; i++ {
992 p.WriteString(p.indent)
993 }
994 }
995 if depthDelta > 0 {
996 p.depth++
997 p.indentedIn = true
998 }
999 }
1000
1001 type parentStack struct {
1002 p *printer
1003 stack []string
1004 }
1005
1006
1007
1008
1009 func (s *parentStack) trim(parents []string) error {
1010 split := 0
1011 for ; split < len(parents) && split < len(s.stack); split++ {
1012 if parents[split] != s.stack[split] {
1013 break
1014 }
1015 }
1016 for i := len(s.stack) - 1; i >= split; i-- {
1017 if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
1018 return err
1019 }
1020 }
1021 s.stack = s.stack[:split]
1022 return nil
1023 }
1024
1025
1026 func (s *parentStack) push(parents []string) error {
1027 for i := 0; i < len(parents); i++ {
1028 if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
1029 return err
1030 }
1031 }
1032 s.stack = append(s.stack, parents...)
1033 return nil
1034 }
1035
1036
1037
1038 type UnsupportedTypeError struct {
1039 Type reflect.Type
1040 }
1041
1042 func (e *UnsupportedTypeError) Error() string {
1043 return "xml: unsupported type: " + e.Type.String()
1044 }
1045
1046 func isEmptyValue(v reflect.Value) bool {
1047 switch v.Kind() {
1048 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
1049 return v.Len() == 0
1050 case reflect.Bool:
1051 return !v.Bool()
1052 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1053 return v.Int() == 0
1054 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1055 return v.Uint() == 0
1056 case reflect.Float32, reflect.Float64:
1057 return v.Float() == 0
1058 case reflect.Interface, reflect.Pointer:
1059 return v.IsNil()
1060 }
1061 return false
1062 }
1063
View as plain text