Skip to content

Commit 9795ff1

Browse files
committed
encoding/xml: fixes to enforce XML namespace standard
All issues of golang#13400 which are not new functionalities have fixes. There are minor incompatibilities between them due to the handling of prefixes. Duplicating a prefix or an namespace is invalid XML. This is now avoided. XML produced is always valid. Tests have been added for each fix and example and previous tests fixed as output is already more compact is some cases. encoding/xml: fix duplication of namespace tags by encoder (golang#7535) A tag prefix identifies the name space of the tag and not the default name space like xmlns="...". Writing the prefix is incorrect when it is bound to a name space using the standard xmlns:prefix="..." attribute. This fix skips this print. Consequences are - duplication is avoided in line with name space standard in reference. - the _xmlns declaration does not appear anymore. To keep the previous behaviour, the prefix is printed in all other cases. Token now always produces well-formed XML except when the explicit name space collides with the prefix. Made prefix handling "xmlns="space" xmlns:_xmlns="xmlns" _..." has be removed in all wants of tests. In some cases, useless declarations like xmlns:x="x" are still added in line with previous behavior. encoding/xml: fix unexpected behavior of encoder.Indent("", "") (golang#13185, golang#11431) MarshalIndent and Marshal share code. When prefix and indent are empty, the behavior is like Marshal when it should have a minimal indent, i.e. new line as in documentation. A boolean is added to the local printer struct which defaults to false. It is set to true only when MarshalIndent is used and prefix and indent are empty. encoding/xml: fix overriding by empty namespace (golang#7113) The namespace defined by xmlns="value" can be overridden in every included tag including by the empty namespace xmlns="". Empty namespace is not authorized with a prefix (xmlns:ns=""). Method to calculate indent of XML handles depth of tag and its associated namespace. The fix leaves the method active even when no indent is required. An XMLName field in a struct means that namespace must be enforced even if empty. This occurs only on an inner tag as an overwrite of any non-empty namespace of its outer tag. To obtain the xmlns="" required, an attribute is added. encoding/xml: fix panic on embedded unexported XMLName (golang#10538) By laws of reflection, unexported fields are unreachable by .Value. XMLName are allowed at any level of an inner struct but the struct may not be reachable. If XMLName field is found without name, it cannot be exported and the value is discarded like other fields. Some comments have been to underline where the issue arises. Another XMLName test was incorrectly set up and is fixed. Various cases added in a specific test. encoding/xml: fix panic of unmarshaling of anonymous structs (golang#16497) Encoding/xml is using type "typinfo" which provides its own "value" method using the reflection package. It fails to check for the documented possible panics of the reflection methods. It is impossible to fix the method as the parameter is also using reflection. The fix is to discard anonymous structs which have no value anyway. Encoder/xml documentation already mentions that fields are accessed using the reflection package. A relevant test is added. encoding/xml: fix closing tag failure (golang#20685) Push/pop of elements name must be done using the eventual prefix together with the tag name. The operation is moved before the translation of prefix into its URI. One end element of a test is fixed as expecting the last used namespace is incorrect. After closing a tag using a namespace, the valid namespace must be taken from the opening tag. encoding/xml: add check of namespaces to detect field names conflicts (golang#8535, golang#11724) Comparing namespaces of fields was missing and false conflicts were detected. encoding/xml: fix invalid empty namespace without prefix (golang#8068) Empty namespace is allowed only if it has no prefix. An error message is now returned if a prefix exists. A similar case when no prefix is provided, thus with syntax xmlns:="..." is also rejected. encoding/xml: fix normalization of attributes values (golang#20614) The attribute value was read as text. The existing attribute reader logic is fixed as an attribute may have a namespace or only a prefix. Other possibilities have been removed. To keep the behavior of raw token which allows many faults in attributes list, error handling is heavily using the Strict parameter of the decoder. Specific tests have been added including list of attributes. To keep the behavior or unmarshal, escaped characters handling has been added but it is not symmetrical to Marshal for quotes but follows XML specification. encoding/xml: fix absence of detection of another : in qualified names (golang#20396) The occurrence of second : in space and tag name is rejected. Fixes: golang#7113, golang#7535, golang#8068, golang#8535, golang#10538, golang#11431, golang#13185, golang#16497, golang#20396, golang#20614, golang#20685 Change-Id: Ib4a60347a47d23ff59b63307cebb83b71c7c9165 Commit originally authored by: Constantin Konstantinidis <[email protected]> encoding/xml: fix printing of namespace prefix in tag names Prefix displays in XML when defined in tag names. The URL of the name space is also returned for an End Token as documentation requires to improve idempotency of Marshal/Unmarshal. Translating the prefix is popping the NS which was unavailable for translation. Translate for an End Token has been moved inside the pop element part. Fixes golang#9519 Change-Id: Id7a14d07c106a76a487b5c4e28d9d563fe061c60 encoding/xml: restore changes lost in merge See golang#43168. encoding/xml: gofmt encoding/xml: minimalIndent -> minIndent to shrink diff encoding/xml: gofmt encoding/xml: revert changes to (*Decoder).attrval from master encoding/xml: restore (*printer).writeIndent to master encoding/xml: remove comments that don’t change functionality of tests encoding/xml: use t.Errorf instead of fmt.Errorf encoding/xml: fix test case for golang#11496
1 parent 8e36ab0 commit 9795ff1

File tree

6 files changed

+915
-77
lines changed

6 files changed

+915
-77
lines changed

src/encoding/xml/marshal.go

+109-24
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ type printer struct {
304304
*bufio.Writer
305305
encoder *Encoder
306306
seq int
307-
indent string
308-
prefix string
307+
indent string // line identation
308+
prefix string // line prefix
309309
depth int
310310
indentedIn bool
311311
putNewline bool
@@ -364,7 +364,7 @@ func (p *printer) createAttrPrefix(url string) string {
364364

365365
p.attrPrefix[url] = prefix
366366
p.attrNS[prefix] = url
367-
367+
/* prints a prefix definition for the URL which had no prefix */
368368
p.WriteString(`xmlns:`)
369369
p.WriteString(prefix)
370370
p.WriteString(`="`)
@@ -382,6 +382,8 @@ func (p *printer) deleteAttrPrefix(prefix string) {
382382
delete(p.attrNS, prefix)
383383
}
384384

385+
// p.prefixes contains prefixes separated by the empty string between tags
386+
// as several prefixes can be defined at any level
385387
func (p *printer) markPrefix() {
386388
p.prefixes = append(p.prefixes, "")
387389
}
@@ -391,12 +393,36 @@ func (p *printer) popPrefix() {
391393
prefix := p.prefixes[len(p.prefixes)-1]
392394
p.prefixes = p.prefixes[:len(p.prefixes)-1]
393395
if prefix == "" {
394-
break
396+
break // end of tag is reached
395397
}
396398
p.deleteAttrPrefix(prefix)
397399
}
398400
}
399401

402+
// No prefix is returned if the first prefix of the list for this tag is not assigned to a namespace
403+
func (p *printer) tagPrefix() string {
404+
prefix := p.prefixes[len(p.prefixes)-1] // last prefix relates to current tag
405+
i := len(p.prefixes) - 1
406+
for i >= 0 && i < len(p.prefixes) {
407+
if prefix == "" { // end of list of prefixes for this tag is reached
408+
// check that previous prefix is the one of the tag
409+
if i+1 < len(p.prefixes) { // list is not empty
410+
if p.attrNS[p.prefixes[i+1]] != "" {
411+
// prefix has been created, i.e. no prefix for the tag
412+
return ""
413+
} else {
414+
return p.prefixes[i+1]
415+
}
416+
} else {
417+
return ""
418+
}
419+
}
420+
i--
421+
prefix = p.prefixes[i]
422+
}
423+
return ""
424+
}
425+
400426
var (
401427
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
402428
marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem()
@@ -482,17 +508,23 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
482508
xmlname := tinfo.xmlname
483509
if xmlname.name != "" {
484510
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
511+
// .Space is equivalent to xmlns=".Space" so adding the attribute
512+
if start.Name.Space != "" {
513+
start.Attr = append(start.Attr, Attr{Name{"", xmlnsPrefix}, start.Name.Space})
514+
}
485515
} else {
486516
fv := xmlname.value(val, dontInitNilPointers)
487517
if v, ok := fv.Interface().(Name); ok && v.Local != "" {
488518
start.Name = v
489519
}
490520
}
521+
} else {
522+
// No enforced namespace, i.e. the outer tag namespace remains valid
491523
}
492-
if start.Name.Local == "" && finfo != nil {
524+
if start.Name.Local == "" && finfo != nil { // XMLName overrides tag name - anonymous struct
493525
start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
494526
}
495-
if start.Name.Local == "" {
527+
if start.Name.Local == "" { // No or empty XMLName and still no tag name
496528
name := typ.Name()
497529
if i := strings.IndexByte(name, '['); i >= 0 {
498530
// Truncate generic instantiation name. See issue 48318.
@@ -526,6 +558,13 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
526558
}
527559
}
528560

561+
/* If an xmlname was found, namespace must be overridden */
562+
if tinfo.xmlname != nil && start.Name.Space == "" &&
563+
len(p.tags) != 0 && p.tags[len(p.tags)-1].Space != "" {
564+
//add attr xmlns="" to override the outer tag namespace
565+
start.Attr = append(start.Attr, Attr{Name{"", xmlnsPrefix}, ""})
566+
}
567+
/* */
529568
if err := p.writeStart(&start); err != nil {
530569
return err
531570
}
@@ -698,31 +737,70 @@ func (p *printer) writeStart(start *StartElement) error {
698737
return fmt.Errorf("xml: start tag with no name")
699738
}
700739

740+
// Pushes the value (url) of the namespace and not the eventual prefix
701741
p.tags = append(p.tags, start.Name)
702-
p.markPrefix()
742+
p.markPrefix() // pushes an empty prefix to allow pop to locate the end of any prefix
703743

704-
p.writeIndent(1)
744+
p.writeIndent(1) // handling relative depth of a tag
705745
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('"')
746+
/* The attribute was not added if no XMLName field existed. */
747+
var tagSpaceAttr Attr // the attribute will not be printed to avoid repetition
748+
if start.Name.Space != "" { // tag starts with <.Space:.Local
749+
// Locate an eventual prefix. If none, the XML is <tag name and no short notation is used.
750+
prefixToPrint := ""
751+
for _, attr := range start.Attr {
752+
// tag .Space only contains a namespace URL and the prefix is unavailable
753+
// (xmlns:(unavailable)=.Space)
754+
// Attributes values which are namespaces are searched to avoid reprinting the domain
755+
// The first attribute with a value == to start tag token will be the prefix used
756+
// Print the space definition if the prefix is used
757+
if start.Name.Space == attr.Value && attr.Name.Space == xmlnsPrefix && attr.Name.Local != "" {
758+
// this is not enough if you return End tag with url in space and not the prefix
759+
prefixToPrint = attr.Name.Local // if you skip printing, the value of the prefix does not display
760+
p.prefixes = append(p.prefixes, prefixToPrint) // xmlns(.Space):(.Local)=(.Value)
761+
break // the first prefix found is used
762+
}
763+
}
764+
if prefixToPrint == "" { // no prefix was found for the space of the tag name
765+
// the tag name Space is then considered as the default xmlns=".Space"
766+
for _, attr := range start.Attr {
767+
// attributes values which are namespaces are searched to avoid reprinting the default
768+
if start.Name.Space == attr.Value && attr.Name.Space == "" && attr.Name.Local == xmlnsPrefix {
769+
tagSpaceAttr = attr
770+
}
771+
break // the first attribute which is a default declaration that matches is kept
772+
}
773+
}
774+
if prefixToPrint != "" {
775+
// print the prefix and not the namespace value
776+
p.WriteString(prefixToPrint)
777+
p.WriteByte(':')
778+
p.WriteString(start.Name.Local) // tag name
779+
} else {
780+
p.WriteString(start.Name.Local) // no prefix found
781+
p.WriteString(` xmlns="`) // printing the namespace taken as default without prefix
782+
p.EscapeString(start.Name.Space)
783+
p.WriteByte('"')
784+
}
785+
} else {
786+
p.WriteString(start.Name.Local) // tag name
712787
}
713788

714789
// Attributes
715790
for _, attr := range start.Attr {
716-
name := attr.Name
717-
if name.Local == "" {
718-
continue
791+
if attr.Name.Local == "" || attr == tagSpaceAttr {
792+
continue // attribute already printed
719793
}
720794
p.WriteByte(' ')
721-
if name.Space != "" {
722-
p.WriteString(p.createAttrPrefix(name.Space))
795+
if attr.Name.Space == xmlnsPrefix { // printing prefix name.Local xmlns:{.Local}={.Value}
796+
p.WriteString(xmlnsPrefix)
723797
p.WriteByte(':')
798+
} else if attr.Name.Space != "" { // not a name space {.Space}:{.Local}={.Value} and .Local is not xmlns
799+
p.WriteString(p.createAttrPrefix(attr.Name.Space)) // name.Space is not a prefix but nothing should be done
800+
p.WriteByte(':') // about it if another one exists
724801
}
725-
p.WriteString(name.Local)
802+
// When space is empty, only writing .Local=.Value which will also be xmlns=".Value"
803+
p.WriteString(attr.Name.Local)
726804
p.WriteString(`="`)
727805
p.EscapeString(attr.Value)
728806
p.WriteByte('"')
@@ -738,17 +816,24 @@ func (p *printer) writeEnd(name Name) error {
738816
if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
739817
return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
740818
}
741-
if top := p.tags[len(p.tags)-1]; top != name {
742-
if top.Local != name.Local {
819+
if top := p.tags[len(p.tags)-1]; top != name { // the end tag must check the prefix value when there is one
820+
if top.Local != name.Local { // Tag names do not match
743821
return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
822+
} // Namespaces do not match
823+
if top.Space != name.Space { // tag prefixes do not match
824+
return fmt.Errorf("xml: end space </%s> does not match start space <%s>", name.Space, top.Space)
744825
}
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)
746826
}
747-
p.tags = p.tags[:len(p.tags)-1]
748827

749828
p.writeIndent(-1)
750829
p.WriteByte('<')
751830
p.WriteByte('/')
831+
endPrefix := p.tagPrefix()
832+
if name.Space != "" && endPrefix != "" { // a prefix is available
833+
p.WriteString(endPrefix) // print the prefix and not its value
834+
p.WriteByte(':')
835+
} // otherwise, xmlns=".Space" has no prefix and nothing should be printed
836+
p.tags = p.tags[:len(p.tags)-1]
752837
p.WriteString(name.Local)
753838
p.WriteByte('>')
754839
p.popPrefix()

src/encoding/xml/marshal_test.go

+24-17
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,11 @@ var marshalTests = []struct {
629629
{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
630630
{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
631631
{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
632+
// Marshal is not symetric to Unmarshal for these oddities because &apos is written as &#39
633+
{Value: &Port{Type: "<un'ix>"}, ExpectXML: `<port type="&lt;un&apos;ix&gt;"></port>`, UnmarshalOnly: true},
634+
{Value: &Port{Type: "<un\"ix>"}, ExpectXML: `<port type="&lt;un&quot;ix&gt;"></port>`, UnmarshalOnly: true},
635+
{Value: &Port{Type: "<un&ix>"}, ExpectXML: `<port type="&lt;un&amp;ix&gt;"></port>`},
636+
{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`, UnmarshalOnly: true},
632637
{Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
633638
{Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
634639
{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
@@ -1107,10 +1112,10 @@ var marshalTests = []struct {
11071112
Value: &AnyTest{Nested: "known",
11081113
AnyField: AnyHolder{
11091114
XML: "<unknown/>",
1110-
XMLName: Name{Local: "AnyField"},
1115+
XMLName: Name{Local: "other"}, // Overriding the field name is the purpose of the test
11111116
},
11121117
},
1113-
ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
1118+
ExpectXML: `<a><nested><value>known</value></nested><other><unknown/></other></a>`,
11141119
},
11151120
{
11161121
ExpectXML: `<a><nested><value>b</value></nested></a>`,
@@ -2058,7 +2063,7 @@ var encodeTokenTests = []struct {
20582063
StartElement{Name{"space", "foo"}, nil},
20592064
EndElement{Name{"another", "foo"}},
20602065
},
2061-
err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
2066+
err: "xml: end space </another> does not match start space <space>",
20622067
want: `<foo xmlns="space">`,
20632068
}, {
20642069
desc: "start element with explicit namespace",
@@ -2068,7 +2073,7 @@ var encodeTokenTests = []struct {
20682073
{Name{"space", "foo"}, "value"},
20692074
}},
20702075
},
2071-
want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
2076+
want: `<x:local xmlns:x="space" xmlns:space="space" space:foo="value">`,
20722077
}, {
20732078
desc: "start element with explicit namespace and colliding prefix",
20742079
toks: []Token{
@@ -2078,7 +2083,8 @@ var encodeTokenTests = []struct {
20782083
{Name{"x", "bar"}, "other"},
20792084
}},
20802085
},
2081-
want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
2086+
// #17 Removed version was not well-formed as x is bound to "space" and to "x"
2087+
want: `<x:local xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
20822088
}, {
20832089
desc: "start element using previously defined namespace",
20842090
toks: []Token{
@@ -2089,7 +2095,8 @@ var encodeTokenTests = []struct {
20892095
{Name{"space", "x"}, "y"},
20902096
}},
20912097
},
2092-
want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
2098+
// #18 The well-formed prefix is the only one appearing and the prefix is not in the tag as .Space is empty
2099+
want: `<local xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
20932100
}, {
20942101
desc: "nested name space with same prefix",
20952102
toks: []Token{
@@ -2110,7 +2117,7 @@ var encodeTokenTests = []struct {
21102117
{Name{"space2", "b"}, "space2 value"},
21112118
}},
21122119
},
2113-
want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space1"><foo _xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value"></foo></foo><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value">`,
2120+
want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value"></foo></foo><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value">`,
21142121
}, {
21152122
desc: "start element defining several prefixes for the same name space",
21162123
toks: []Token{
@@ -2120,7 +2127,7 @@ var encodeTokenTests = []struct {
21202127
{Name{"space", "x"}, "value"},
21212128
}},
21222129
},
2123-
want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
2130+
want: `<a:foo xmlns:a="space" xmlns:b="space" xmlns:space="space" space:x="value">`,
21242131
}, {
21252132
desc: "nested element redefines name space",
21262133
toks: []Token{
@@ -2132,7 +2139,7 @@ var encodeTokenTests = []struct {
21322139
{Name{"space", "a"}, "value"},
21332140
}},
21342141
},
2135-
want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2142+
want: `<foo xmlns:x="space"><y:foo xmlns:y="space" xmlns:space="space" space:a="value">`,
21362143
}, {
21372144
desc: "nested element creates alias for default name space",
21382145
toks: []Token{
@@ -2144,7 +2151,7 @@ var encodeTokenTests = []struct {
21442151
{Name{"space", "a"}, "value"},
21452152
}},
21462153
},
2147-
want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2154+
want: `<foo xmlns="space"><y:foo xmlns:y="space" xmlns:space="space" space:a="value">`,
21482155
}, {
21492156
desc: "nested element defines default name space with existing prefix",
21502157
toks: []Token{
@@ -2156,7 +2163,7 @@ var encodeTokenTests = []struct {
21562163
{Name{"space", "a"}, "value"},
21572164
}},
21582165
},
2159-
want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
2166+
want: `<foo xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:a="value">`,
21602167
}, {
21612168
desc: "nested element uses empty attribute name space when default ns defined",
21622169
toks: []Token{
@@ -2167,7 +2174,7 @@ var encodeTokenTests = []struct {
21672174
{Name{"", "attr"}, "value"},
21682175
}},
21692176
},
2170-
want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
2177+
want: `<foo xmlns="space"><foo xmlns="space" attr="value">`,
21712178
}, {
21722179
desc: "redefine xmlns",
21732180
toks: []Token{
@@ -2199,7 +2206,7 @@ var encodeTokenTests = []struct {
21992206
{Name{"xmlns", "foo"}, ""},
22002207
}},
22012208
},
2202-
want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
2209+
want: `<foo xmlns:foo="">`,
22032210
}, {
22042211
desc: "attribute with no name is ignored",
22052212
toks: []Token{
@@ -2228,7 +2235,7 @@ var encodeTokenTests = []struct {
22282235
{Name{"space", "x"}, "value"},
22292236
}},
22302237
},
2231-
want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
2238+
want: `<foo xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
22322239
}, {
22332240
desc: "nested element requires empty default name space",
22342241
toks: []Token{
@@ -2237,7 +2244,7 @@ var encodeTokenTests = []struct {
22372244
}},
22382245
StartElement{Name{"", "foo"}, nil},
22392246
},
2240-
want: `<foo xmlns="space" xmlns="space"><foo>`,
2247+
want: `<foo xmlns="space"><foo>`,
22412248
}, {
22422249
desc: "attribute uses name space from xmlns",
22432250
toks: []Token{
@@ -2259,7 +2266,7 @@ var encodeTokenTests = []struct {
22592266
EndElement{Name{"space", "baz"}},
22602267
EndElement{Name{"space", "foo"}},
22612268
},
2262-
want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2269+
want: `<bar:foo xmlns="space" xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></bar:foo>`,
22632270
}, {
22642271
desc: "default name space not used by attributes, not explicitly defined",
22652272
toks: []Token{
@@ -2271,7 +2278,7 @@ var encodeTokenTests = []struct {
22712278
EndElement{Name{"space", "baz"}},
22722279
EndElement{Name{"space", "foo"}},
22732280
},
2274-
want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2281+
want: `<foo xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
22752282
}, {
22762283
desc: "impossible xmlns declaration",
22772284
toks: []Token{

0 commit comments

Comments
 (0)