Skip to content

Unmarshalling of a nil value does not work inside the XML namespace. #1

@VadimKulagin

Description

@VadimKulagin

I get about such an XML response from the API:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetSomeXMLResponse xmlns="http://example.com">
            <GetSomeXMLResponseResult>
                <SomeContainersHere xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="">
                    <row SomeContainerID="111">
                        <Items>
                            <row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ItemID="222">
                                <NonNilValue>5.700000000000000e-001</NonNilValue>
                                <NilValue xsi:nil="true" />
                            </row>
                            <row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ItemID="333">
                                <NonNilValue>2.700000000000000e-001</NonNilValue>
                                <NilValue xsi:nil="true" />
                            </row>
                        </Items>
                    </row>
                </SomeContainersHere>
            </GetSomeXMLResponseResult>
        </GetSomeXMLResponse>
    </soap:Body>
</soap:Envelope>

All this is parsed into something like this:

type Item struct {
	ID          int64        `xml:"ItemID,attr"`
	NonNilValue float64      `xml:"NonNilValue"`
	NilValue    null.Float64 `xml:"NilValue"`
}

However, parsing xsi:nil="true" does not work, because xsi (as I understand it) is a namespace http://www.w3.org/2001/XMLSchema-instance here.

This is evident if you add logging:

func (f *Float64) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	for _, attr := range start.Attr {
		log.Printf("attr: %#v",attr) // TODO: remove
		if isXsiNilAttr(attr) {
			f.Float64, f.Valid = 0, false
			return d.Skip()
		}
	}
	f.Valid = true
	return d.DecodeElement(&f.Float64, &start)
}
attr: xml.Attr{Name:xml.Name{Space:"http://www.w3.org/2001/XMLSchema-instance", Local:"nil"}, Value:"true"}

To make it work, I had to do this hack:

func isXsiNilAttr(attr xml.Attr) bool {
	return (attr.Name.Space == "xsi" || attr.Name.Space == "http://www.w3.org/2001/XMLSchema-instance") &&
		attr.Name.Local == "nil" && attr.Value == "true"
}

But I think it's worth doing better and it's worth taking into account in the tests.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions