Index: src/pkg/encoding/xml/marshal.go |
=================================================================== |
--- a/src/pkg/encoding/xml/marshal.go |
+++ b/src/pkg/encoding/xml/marshal.go |
@@ -258,6 +258,7 @@ |
putNewline bool |
attrNS map[string]string // map prefix -> name space |
attrPrefix map[string]string // map name space -> prefix |
+ defaultNS string // current default name space |
prefixes []string |
tags []Name |
} |
@@ -322,6 +323,10 @@ |
// deleteAttrPrefix removes an attribute name space prefix. |
func (p *printer) deleteAttrPrefix(prefix string) { |
+ if strings.HasPrefix(prefix, "=ns=") { |
anacrolix
2014/05/13 23:00:23
Is this some kind of special value?
|
+ p.defaultNS = prefix[len("=ns="):] |
+ return |
+ } |
delete(p.attrPrefix, p.attrNS[prefix]) |
delete(p.attrNS, prefix) |
} |
@@ -341,6 +346,21 @@ |
} |
} |
+func (p *printer) pushDefaultNS(ns string) { |
+ p.prefixes = append(p.prefixes, "=ns="+ns) |
+} |
+ |
+func (p *printer) fieldName(f *fieldInfo) Name { |
+ if f.name == "" { |
+ return Name{} |
+ } |
+ space := f.xmlns |
+ if f.xmlnsMissing && f.flags&fAttr == 0 { |
+ space = p.defaultNS |
+ } |
+ return Name{space, f.name} |
+} |
+ |
var ( |
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() |
marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem() |
@@ -376,23 +396,23 @@ |
// Check for marshaler. |
if val.CanInterface() && typ.Implements(marshalerType) { |
- return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate)) |
+ return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate)) |
} |
if val.CanAddr() { |
pv := val.Addr() |
if pv.CanInterface() && pv.Type().Implements(marshalerType) { |
- return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate)) |
+ return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) |
} |
} |
// Check for text marshaler. |
if val.CanInterface() && typ.Implements(textMarshalerType) { |
- return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate)) |
+ return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate)) |
} |
if val.CanAddr() { |
pv := val.Addr() |
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { |
- return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate)) |
+ return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) |
} |
} |
@@ -425,19 +445,20 @@ |
} else if tinfo.xmlname != nil { |
xmlname := tinfo.xmlname |
if xmlname.name != "" { |
- start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name |
+ start.Name = p.fieldName(xmlname) |
} else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { |
start.Name = v |
} |
} |
if start.Name.Local == "" && finfo != nil { |
- start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name |
+ start.Name = p.fieldName(finfo) |
} |
if start.Name.Local == "" { |
name := typ.Name() |
if name == "" { |
return &UnsupportedTypeError{typ} |
} |
+ start.Name.Space = p.defaultNS |
start.Name.Local = name |
} |
@@ -448,7 +469,7 @@ |
continue |
} |
fv := finfo.value(val) |
- name := Name{Space: finfo.xmlns, Local: finfo.name} |
+ name := p.fieldName(finfo) |
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { |
continue |
@@ -552,7 +573,7 @@ |
// defaultStart returns the default start element to use, |
// given the reflect type, field info, and start template. |
-func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { |
+func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { |
var start StartElement |
// Precedence for the XML element name is as above, |
// except that we do not look inside structs for the first field. |
@@ -560,13 +581,14 @@ |
start.Name = startTemplate.Name |
start.Attr = append(start.Attr, startTemplate.Attr...) |
} else if finfo != nil && finfo.name != "" { |
- start.Name.Local = finfo.name |
- start.Name.Space = finfo.xmlns |
+ start.Name = p.fieldName(finfo) |
} else if typ.Name() != "" { |
+ start.Name.Space = p.defaultNS |
start.Name.Local = typ.Name() |
} else { |
// Must be a pointer to a named type, |
// since it has the Marshaler methods. |
+ start.Name.Space = p.defaultNS |
start.Name.Local = typ.Elem().Name() |
} |
return start |
@@ -618,8 +640,10 @@ |
p.WriteByte('<') |
p.WriteString(start.Name.Local) |
- if start.Name.Space != "" { |
+ if start.Name.Space != p.defaultNS { |
p.WriteString(` xmlns="`) |
+ p.pushDefaultNS(p.defaultNS) |
+ p.defaultNS = start.Name.Space |
p.EscapeString(start.Name.Space) |
p.WriteByte('"') |
} |
@@ -823,7 +847,7 @@ |
} |
if len(finfo.parents) > len(s.stack) { |
if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() { |
- if err := s.push(finfo.parents[len(s.stack):]); err != nil { |
+ if err := s.push(p.defaultNS, finfo.parents[len(s.stack):]); err != nil { |
return err |
} |
} |
@@ -899,9 +923,9 @@ |
} |
// push adds parent elements to the stack and writes open tags. |
-func (s *parentStack) push(parents []string) error { |
+func (s *parentStack) push(defaultNS string, parents []string) error { |
for i := 0; i < len(parents); i++ { |
- if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil { |
+ if err := s.p.writeStart(&StartElement{Name: Name{Space: defaultNS, Local: parents[i]}}); err != nil { |
return err |
} |
} |