Skip to content

Commit ec036eb

Browse files
feat: unpatched Go 1.16 encoding/xml
Updated package to use encoding/xml from Go 1.16 release. This code has not been patched for SOAP handling yet. This commit is designed to allow the changes made to get SOAP handling working to be easily traced.
1 parent e281504 commit ec036eb

File tree

13 files changed

+244
-50
lines changed

13 files changed

+244
-50
lines changed

LICENSE

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2009 The Go Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google Inc. nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
# xml
2-
[FORK] Modified encoding/xml with better support for SOAP namespaces
1+
# Go encoding/xml
2+
3+
This package is a fork of the Go standard library [encoding/xml](https://github.com/golang/go/tree/master/src/encoding/xml) package.
4+
5+
This fork changes the handling of XML namespaces in Go specifically around the `xml.Name` struct.

example_marshaling_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package xml_test
66

77
import (
8-
"github.com/mattrax/Mattrax/pkg/xml"
8+
"encoding/xml"
99
"fmt"
1010
"log"
1111
"strings"

example_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package xml_test
66

77
import (
8-
"github.com/mattrax/Mattrax/pkg/xml"
8+
"encoding/xml"
99
"fmt"
1010
"os"
1111
)

example_text_marshaling_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package xml_test
66

77
import (
8-
"github.com/mattrax/Mattrax/pkg/xml"
8+
"encoding/xml"
99
"fmt"
1010
"log"
1111
"strings"

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/mattrax/xml
2+
3+
go 1.16

marshal.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,11 @@ func (p *printer) createAttrPrefix(url string) string {
345345
if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
346346
prefix = "_"
347347
}
348-
if strings.HasPrefix(prefix, "xml") {
349-
// xmlanything is reserved.
348+
// xmlanything is reserved and any variant of it regardless of
349+
// case should be matched, so:
350+
// (('X'|'x') ('M'|'m') ('L'|'l'))
351+
// See Section 2.3 of https://www.w3.org/TR/REC-xml/
352+
if len(prefix) >= 3 && strings.EqualFold(prefix[:3], "xml") {
350353
prefix = "_" + prefix
351354
}
352355
if p.attrNS[prefix] != "" {
@@ -479,8 +482,11 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
479482
xmlname := tinfo.xmlname
480483
if xmlname.name != "" {
481484
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
482-
} else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" {
483-
start.Name = v
485+
} else {
486+
fv := xmlname.value(val, dontInitNilPointers)
487+
if v, ok := fv.Interface().(Name); ok && v.Local != "" {
488+
start.Name = v
489+
}
484490
}
485491
}
486492
if start.Name.Local == "" && finfo != nil {
@@ -500,7 +506,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
500506
if finfo.flags&fAttr == 0 {
501507
continue
502508
}
503-
fv := finfo.value(val)
509+
fv := finfo.value(val, dontInitNilPointers)
504510

505511
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
506512
continue
@@ -623,10 +629,6 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
623629
if b != nil {
624630
s = string(b)
625631
}
626-
j := strings.Index(start.Name.Local, ":")
627-
if j > 0 && start.Name.Local[0:j] == name.Local {
628-
name.Local = "xmlns:" + name.Local
629-
}
630632
start.Attr = append(start.Attr, Attr{name, s})
631633
return nil
632634
}
@@ -807,7 +809,12 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
807809
if finfo.flags&fAttr != 0 {
808810
continue
809811
}
810-
vf := finfo.value(val)
812+
vf := finfo.value(val, dontInitNilPointers)
813+
if !vf.IsValid() {
814+
// The field is behind an anonymous struct field that's
815+
// nil. Skip it.
816+
continue
817+
}
811818

812819
switch finfo.flags & fMode {
813820
case fCDATA, fCharData:
@@ -918,7 +925,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
918925
p.WriteString("-->")
919926
continue
920927

921-
case fInnerXml:
928+
case fInnerXML:
922929
vf = indirect(vf)
923930
iface := vf.Interface()
924931
switch raw := iface.(type) {

marshal_test.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ type ChardataEmptyTest struct {
309309
Contents *string `xml:",chardata"`
310310
}
311311

312+
type PointerAnonFields struct {
313+
*MyInt
314+
*NamedType
315+
}
316+
312317
type MyMarshalerTest struct {
313318
}
314319

@@ -392,7 +397,6 @@ func stringptr(x string) *string {
392397

393398
type T1 struct{}
394399
type T2 struct{}
395-
type T3 struct{}
396400

397401
type IndirComment struct {
398402
T1 T1
@@ -890,6 +894,18 @@ var marshalTests = []struct {
890894
`</EmbedA>`,
891895
},
892896

897+
// Anonymous struct pointer field which is nil
898+
{
899+
Value: &EmbedB{},
900+
ExpectXML: `<EmbedB><FieldB></FieldB></EmbedB>`,
901+
},
902+
903+
// Other kinds of nil anonymous fields
904+
{
905+
Value: &PointerAnonFields{},
906+
ExpectXML: `<PointerAnonFields></PointerAnonFields>`,
907+
},
908+
893909
// Test that name casing matters
894910
{
895911
Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
@@ -2267,6 +2283,30 @@ var encodeTokenTests = []struct {
22672283
}},
22682284
},
22692285
want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
2286+
}, {
2287+
desc: "reserved namespace prefix -- all lower case",
2288+
toks: []Token{
2289+
StartElement{Name{"", "foo"}, []Attr{
2290+
{Name{"http://www.w3.org/2001/xmlSchema-instance", "nil"}, "true"},
2291+
}},
2292+
},
2293+
want: `<foo xmlns:_xmlSchema-instance="http://www.w3.org/2001/xmlSchema-instance" _xmlSchema-instance:nil="true">`,
2294+
}, {
2295+
desc: "reserved namespace prefix -- all upper case",
2296+
toks: []Token{
2297+
StartElement{Name{"", "foo"}, []Attr{
2298+
{Name{"http://www.w3.org/2001/XMLSchema-instance", "nil"}, "true"},
2299+
}},
2300+
},
2301+
want: `<foo xmlns:_XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" _XMLSchema-instance:nil="true">`,
2302+
}, {
2303+
desc: "reserved namespace prefix -- all mixed case",
2304+
toks: []Token{
2305+
StartElement{Name{"", "foo"}, []Attr{
2306+
{Name{"http://www.w3.org/2001/XmLSchema-instance", "nil"}, "true"},
2307+
}},
2308+
},
2309+
want: `<foo xmlns:_XmLSchema-instance="http://www.w3.org/2001/XmLSchema-instance" _XmLSchema-instance:nil="true">`,
22702310
}}
22712311

22722312
func TestEncodeToken(t *testing.T) {

read.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
435435
}
436436
return UnmarshalError(e)
437437
}
438-
fv := finfo.value(sv)
438+
fv := finfo.value(sv, initNilPointers)
439439
if _, ok := fv.Interface().(Name); ok {
440440
fv.Set(reflect.ValueOf(start.Name))
441441
}
@@ -449,7 +449,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
449449
finfo := &tinfo.fields[i]
450450
switch finfo.flags & fMode {
451451
case fAttr:
452-
strv := finfo.value(sv)
452+
strv := finfo.value(sv, initNilPointers)
453453
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
454454
if err := d.unmarshalAttr(strv, a); err != nil {
455455
return err
@@ -465,7 +465,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
465465
}
466466
if !handled && any >= 0 {
467467
finfo := &tinfo.fields[any]
468-
strv := finfo.value(sv)
468+
strv := finfo.value(sv, initNilPointers)
469469
if err := d.unmarshalAttr(strv, a); err != nil {
470470
return err
471471
}
@@ -478,22 +478,22 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
478478
switch finfo.flags & fMode {
479479
case fCDATA, fCharData:
480480
if !saveData.IsValid() {
481-
saveData = finfo.value(sv)
481+
saveData = finfo.value(sv, initNilPointers)
482482
}
483483

484484
case fComment:
485485
if !saveComment.IsValid() {
486-
saveComment = finfo.value(sv)
486+
saveComment = finfo.value(sv, initNilPointers)
487487
}
488488

489489
case fAny, fAny | fElement:
490490
if !saveAny.IsValid() {
491-
saveAny = finfo.value(sv)
491+
saveAny = finfo.value(sv, initNilPointers)
492492
}
493493

494-
case fInnerXml:
494+
case fInnerXML:
495495
if !saveXML.IsValid() {
496-
saveXML = finfo.value(sv)
496+
saveXML = finfo.value(sv, initNilPointers)
497497
if d.saved == nil {
498498
saveXMLIndex = 0
499499
d.saved = new(bytes.Buffer)
@@ -687,7 +687,7 @@ Loop:
687687
}
688688
if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
689689
// It's a perfect match, unmarshal the field.
690-
return true, d.unmarshal(finfo.value(sv), start)
690+
return true, d.unmarshal(finfo.value(sv, initNilPointers), start)
691691
}
692692
if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
693693
// It's a prefix for the field. Break and recurse

read_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ var tables = []struct {
431431
`<f:table>world</f:table>` +
432432
`<h:table>hello</h:table>` +
433433
`</Tables>`,
434-
tab: Tables{}, // TODO
434+
tab: Tables{"hello", "world"},
435435
},
436436
{
437437
xml: `<Tables>` +

0 commit comments

Comments
 (0)