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