@@ -578,12 +578,14 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
578
578
// 3. type name
579
579
var start StartElement
580
580
581
- // Historic behaviour: elements use the default name space
582
- // they are contained in by default.
583
- start .Name .Space = p .defaultNS
581
+ // explicitNS records whether the element's name
582
+ // space has been explicitly set (for example an
583
+ // and XMLName field).
584
+ explicitNS := false
584
585
585
586
if startTemplate != nil {
586
587
start .Name = startTemplate .Name
588
+ explicitNS = true
587
589
start .Attr = append (start .Attr , startTemplate .Attr ... )
588
590
} else if tinfo .xmlname != nil {
589
591
xmlname := tinfo .xmlname
@@ -592,11 +594,13 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
592
594
} else if v , ok := xmlname .value (val ).Interface ().(Name ); ok && v .Local != "" {
593
595
start .Name = v
594
596
}
597
+ explicitNS = true
595
598
}
596
599
if start .Name .Local == "" && finfo != nil {
597
600
start .Name .Local = finfo .name
598
601
if finfo .xmlns != "" {
599
602
start .Name .Space = finfo .xmlns
603
+ explicitNS = true
600
604
}
601
605
}
602
606
if start .Name .Local == "" {
@@ -606,91 +610,39 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
606
610
}
607
611
start .Name .Local = name
608
612
}
609
- // Historic behaviour: an element that's in a namespace sets
610
- // the default namespace for all elements contained within it.
611
- start .setDefaultNamespace ()
613
+
614
+ // defaultNS records the default name space as set by a xmlns="..."
615
+ // attribute. We don't set p.defaultNS because we want to let
616
+ // the attribute writing code (in p.defineNS) be solely responsible
617
+ // for maintaining that.
618
+ defaultNS := p .defaultNS
612
619
613
620
// Attributes
614
621
for i := range tinfo .fields {
615
622
finfo := & tinfo .fields [i ]
616
623
if finfo .flags & fAttr == 0 {
617
624
continue
618
625
}
619
- fv := finfo .value (val )
620
- name := Name {Space : finfo .xmlns , Local : finfo .name }
621
-
622
- if finfo .flags & fOmitEmpty != 0 && isEmptyValue (fv ) {
623
- continue
624
- }
625
-
626
- if fv .Kind () == reflect .Interface && fv .IsNil () {
627
- continue
628
- }
629
-
630
- if fv .CanInterface () && fv .Type ().Implements (marshalerAttrType ) {
631
- attr , err := fv .Interface ().(MarshalerAttr ).MarshalXMLAttr (name )
632
- if err != nil {
633
- return err
634
- }
635
- if attr .Name .Local != "" {
636
- start .Attr = append (start .Attr , attr )
637
- }
638
- continue
639
- }
640
-
641
- if fv .CanAddr () {
642
- pv := fv .Addr ()
643
- if pv .CanInterface () && pv .Type ().Implements (marshalerAttrType ) {
644
- attr , err := pv .Interface ().(MarshalerAttr ).MarshalXMLAttr (name )
645
- if err != nil {
646
- return err
647
- }
648
- if attr .Name .Local != "" {
649
- start .Attr = append (start .Attr , attr )
650
- }
651
- continue
652
- }
653
- }
654
-
655
- if fv .CanInterface () && fv .Type ().Implements (textMarshalerType ) {
656
- text , err := fv .Interface ().(encoding.TextMarshaler ).MarshalText ()
657
- if err != nil {
658
- return err
659
- }
660
- start .Attr = append (start .Attr , Attr {name , string (text )})
661
- continue
662
- }
663
-
664
- if fv .CanAddr () {
665
- pv := fv .Addr ()
666
- if pv .CanInterface () && pv .Type ().Implements (textMarshalerType ) {
667
- text , err := pv .Interface ().(encoding.TextMarshaler ).MarshalText ()
668
- if err != nil {
669
- return err
670
- }
671
- start .Attr = append (start .Attr , Attr {name , string (text )})
672
- continue
673
- }
674
- }
675
-
676
- // Dereference or skip nil pointer, interface values.
677
- switch fv .Kind () {
678
- case reflect .Ptr , reflect .Interface :
679
- if fv .IsNil () {
680
- continue
681
- }
682
- fv = fv .Elem ()
683
- }
684
-
685
- s , b , err := p .marshalSimple (fv .Type (), fv )
626
+ attr , add , err := p .fieldAttr (finfo , val )
686
627
if err != nil {
687
628
return err
688
629
}
689
- if b != nil {
690
- s = string (b )
630
+ if ! add {
631
+ continue
632
+ }
633
+ start .Attr = append (start .Attr , attr )
634
+ if attr .Name .Space == "" && attr .Name .Local == "xmlns" {
635
+ defaultNS = attr .Value
691
636
}
692
- start .Attr = append (start .Attr , Attr {name , s })
693
637
}
638
+ if ! explicitNS {
639
+ // Historic behavior: elements use the default name space
640
+ // they are contained in by default.
641
+ start .Name .Space = defaultNS
642
+ }
643
+ // Historic behaviour: an element that's in a namespace sets
644
+ // the default namespace for all elements contained within it.
645
+ start .setDefaultNamespace ()
694
646
695
647
if err := p .writeStart (& start ); err != nil {
696
648
return err
@@ -719,6 +671,64 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
719
671
return p .cachedWriteError ()
720
672
}
721
673
674
+ // fieldAttr returns the attribute of the given field and
675
+ // whether it should actually be added as an attribute;
676
+ // val holds the value containing the field.
677
+ func (p * printer ) fieldAttr (finfo * fieldInfo , val reflect.Value ) (Attr , bool , error ) {
678
+ fv := finfo .value (val )
679
+ name := Name {Space : finfo .xmlns , Local : finfo .name }
680
+ if finfo .flags & fOmitEmpty != 0 && isEmptyValue (fv ) {
681
+ return Attr {}, false , nil
682
+ }
683
+ if fv .Kind () == reflect .Interface && fv .IsNil () {
684
+ return Attr {}, false , nil
685
+ }
686
+ if fv .CanInterface () && fv .Type ().Implements (marshalerAttrType ) {
687
+ attr , err := fv .Interface ().(MarshalerAttr ).MarshalXMLAttr (name )
688
+ return attr , attr .Name .Local != "" , err
689
+ }
690
+ if fv .CanAddr () {
691
+ pv := fv .Addr ()
692
+ if pv .CanInterface () && pv .Type ().Implements (marshalerAttrType ) {
693
+ attr , err := pv .Interface ().(MarshalerAttr ).MarshalXMLAttr (name )
694
+ return attr , attr .Name .Local != "" , err
695
+ }
696
+ }
697
+ if fv .CanInterface () && fv .Type ().Implements (textMarshalerType ) {
698
+ text , err := fv .Interface ().(encoding.TextMarshaler ).MarshalText ()
699
+ if err != nil {
700
+ return Attr {}, false , err
701
+ }
702
+ return Attr {name , string (text )}, true , nil
703
+ }
704
+ if fv .CanAddr () {
705
+ pv := fv .Addr ()
706
+ if pv .CanInterface () && pv .Type ().Implements (textMarshalerType ) {
707
+ text , err := pv .Interface ().(encoding.TextMarshaler ).MarshalText ()
708
+ if err != nil {
709
+ return Attr {}, false , err
710
+ }
711
+ return Attr {name , string (text )}, true , nil
712
+ }
713
+ }
714
+ // Dereference or skip nil pointer, interface values.
715
+ switch fv .Kind () {
716
+ case reflect .Ptr , reflect .Interface :
717
+ if fv .IsNil () {
718
+ return Attr {}, false , nil
719
+ }
720
+ fv = fv .Elem ()
721
+ }
722
+ s , b , err := p .marshalSimple (fv .Type (), fv )
723
+ if err != nil {
724
+ return Attr {}, false , err
725
+ }
726
+ if b != nil {
727
+ s = string (b )
728
+ }
729
+ return Attr {name , s }, true , nil
730
+ }
731
+
722
732
// defaultStart returns the default start element to use,
723
733
// given the reflect type, field info, and start template.
724
734
func (p * printer ) defaultStart (typ reflect.Type , finfo * fieldInfo , startTemplate * StartElement ) StartElement {
0 commit comments