Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly using namespaces when unmarshaling in XML #954

Merged
merged 1 commit into from
Nov 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion private/protocol/xml/xmlutil/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {

if elems == nil { // try to find the field in attributes
for _, a := range node.Attr {
if name == a.Name.Local {
if name == strings.Join([]string{a.Name.Space, a.Name.Local}, ":") {
// turn this into a text node for de-serializing
elems = []*XMLNode{{Text: a.Value}}
}
Expand Down
22 changes: 22 additions & 0 deletions private/protocol/xml/xmlutil/xml_to_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
return out, e
}
node.Name = typed.Name
node.Attr = out.Attr
node = adaptNode(node)
slice = append(slice, node)
out.Children[name] = slice
case xml.EndElement:
Expand All @@ -74,6 +76,26 @@ func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
return out, nil
}

func adaptNode(node *XMLNode) *XMLNode {
ns := map[string]string{}
for _, a := range node.Attr {
if a.Name.Space == "xmlns" {
ns[a.Value] = a.Name.Local
break
}
}

for i, a := range node.Attr {
if a.Name.Space == "xmlns" {
continue
}
if v, ok := ns[node.Attr[i].Name.Space]; ok {
node.Attr[i].Name.Space = v
}
}
return node
}

// StructToXML writes an XMLNode to a xml.Encoder as tokens.
func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
Expand Down
53 changes: 53 additions & 0 deletions private/protocol/xml/xmlutil/xml_to_struct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package xmlutil_test

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/service/s3"
)

func TestUnmarshal(t *testing.T) {
xmlVal := []byte(`<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>foo-id</ID><DisplayName>user</DisplayName></Owner><AccessControlList><Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="type"><ID>foo-id</ID><DisplayName>user</DisplayName></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList><
/AccessControlPolicy>`)

var server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(xmlVal)
}))

sess := unit.Session
sess.Config.Endpoint = &server.URL
sess.Config.S3ForcePathStyle = aws.Bool(true)
svc := s3.New(sess)

out, err := svc.GetBucketAcl(&s3.GetBucketAclInput{
Bucket: aws.String("foo"),
})

assert.NoError(t, err)

expected := &s3.GetBucketAclOutput{
Grants: []*s3.Grant{
&s3.Grant{
Grantee: &s3.Grantee{
DisplayName: aws.String("user"),
ID: aws.String("foo-id"),
Type: aws.String("type"),
},
Permission: aws.String("FULL_CONTROL"),
},
},

Owner: &s3.Owner{
DisplayName: aws.String("user"),
ID: aws.String("foo-id"),
},
}
assert.Equal(t, expected, out)
}