@@ -1018,25 +1018,22 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
1018
1018
}
1019
1019
1020
1020
case fElement , fElement | fAny :
1021
- if err := s .trim (finfo . parents ); err != nil {
1021
+ if err := s .setParents (finfo , vf ); err != nil {
1022
1022
return err
1023
1023
}
1024
- if len (finfo .parents ) > len (s .stack ) {
1025
- if vf .Kind () != reflect .Ptr && vf .Kind () != reflect .Interface || ! vf .IsNil () {
1026
- if err := s .push (finfo .parents [len (s .stack ):]); err != nil {
1027
- return err
1028
- }
1029
- }
1030
- }
1031
1024
}
1032
1025
if err := p .marshalValue (vf , finfo , nil ); err != nil {
1033
1026
return err
1034
1027
}
1035
1028
}
1036
- s .trim (nil )
1029
+ if err := s .setParents (& noField , reflect.Value {}); err != nil {
1030
+ return err
1031
+ }
1037
1032
return p .cachedWriteError ()
1038
1033
}
1039
1034
1035
+ var noField fieldInfo
1036
+
1040
1037
// return the bufio Writer's cached write error
1041
1038
func (p * printer ) cachedWriteError () error {
1042
1039
_ , err := p .Write (nil )
@@ -1075,37 +1072,64 @@ func (p *printer) writeIndent(depthDelta int) {
1075
1072
}
1076
1073
1077
1074
type parentStack struct {
1078
- p * printer
1079
- stack []string
1075
+ p * printer
1076
+ xmlns string
1077
+ parents []string
1080
1078
}
1081
1079
1082
- // trim updates the XML context to match the longest common prefix of the stack
1083
- // and the given parents. A closing tag will be written for every parent
1084
- // popped. Passing a zero slice or nil will close all the elements.
1085
- func (s * parentStack ) trim (parents []string ) error {
1086
- split := 0
1087
- for ; split < len (parents ) && split < len (s .stack ); split ++ {
1088
- if parents [split ] != s .stack [split ] {
1089
- break
1080
+ // setParents sets the stack of current parents to those found in finfo.
1081
+ // It only writes the start elements if vf holds a non-nil value.
1082
+ // If finfo is &noField, it pops all elements.
1083
+ func (s * parentStack ) setParents (finfo * fieldInfo , vf reflect.Value ) error {
1084
+ xmlns := s .p .defaultNS
1085
+ if finfo .xmlns != "" {
1086
+ xmlns = finfo .xmlns
1087
+ }
1088
+ commonParents := 0
1089
+ if xmlns == s .xmlns {
1090
+ for ; commonParents < len (finfo .parents ) && commonParents < len (s .parents ); commonParents ++ {
1091
+ if finfo .parents [commonParents ] != s .parents [commonParents ] {
1092
+ break
1093
+ }
1090
1094
}
1091
1095
}
1092
- for i := len (s .stack ) - 1 ; i >= split ; i -- {
1093
- if err := s .p .writeEnd (Name {Local : s .stack [i ]}); err != nil {
1096
+ // Pop off any parents that aren't in common with the previous field.
1097
+ for i := len (s .parents ) - 1 ; i >= commonParents ; i -- {
1098
+ if err := s .p .writeEnd (Name {
1099
+ Space : s .xmlns ,
1100
+ Local : s .parents [i ],
1101
+ }); err != nil {
1094
1102
return err
1095
1103
}
1096
1104
}
1097
- s .stack = parents [:split ]
1098
- return nil
1099
- }
1100
-
1101
- // push adds parent elements to the stack and writes open tags.
1102
- func (s * parentStack ) push (parents []string ) error {
1103
- for i := 0 ; i < len (parents ); i ++ {
1104
- if err := s .p .writeStart (& StartElement {Name : Name {Local : parents [i ]}}); err != nil {
1105
+ s .parents = finfo .parents
1106
+ s .xmlns = xmlns
1107
+ if commonParents >= len (s .parents ) {
1108
+ // No new elements to push.
1109
+ return nil
1110
+ }
1111
+ if (vf .Kind () == reflect .Ptr || vf .Kind () == reflect .Interface ) && vf .IsNil () {
1112
+ // The element is nil, so no need for the start elements.
1113
+ s .parents = s .parents [:commonParents ]
1114
+ return nil
1115
+ }
1116
+ // Push any new parents required.
1117
+ for _ , name := range s .parents [commonParents :] {
1118
+ start := & StartElement {
1119
+ Name : Name {
1120
+ Space : s .xmlns ,
1121
+ Local : name ,
1122
+ },
1123
+ }
1124
+ // Set the default name space for parent elements
1125
+ // to match what we do with other elements.
1126
+ if s .xmlns != s .p .defaultNS {
1127
+ start .setDefaultNamespace ()
1128
+ }
1129
+ if err := s .p .writeStart (start ); err != nil {
1105
1130
return err
1106
1131
}
1107
1132
}
1108
- s .stack = append (s .stack , parents ... )
1109
1133
return nil
1110
1134
}
1111
1135
0 commit comments