Golang: Unmarshal Self Closing Tags

According to this discussion this behaviour is not supported and the only reason you don't see an error is that you mispelled committed in the struct definition. If you write it correctly you will get a parse error because an empty string (the contents of a closed tag) is not a boolean value (example on play).

In the linked golang-nuts thread rsc suggests to use *struct{} (a pointer to an empty struct) and check if that value is nil (example on play):

type Location struct {
    Id        string    `xml:"id,attr"`
    Committed *struct{} `xml:"committed"`
    Urgent    bool      `xml:"urgent"`
}

if l.Committed != nil {
    // handle not committed
}

For simple boolean values, i.e. value is true when an element is present, I have solved it this way:

Example XML:

<struct>
    <hide/>
    <data>Value</data>
</struct>

Data structure in Go:

type XMLValues struct {
    Hide BoolIfElementPresent `xml:"hide"`
    Data string               `xml:"data"`
}

type BoolIfElementPresent struct {
    bool
}

func (c *BoolIfElementPresent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var v string
    d.DecodeElement(&v, &start)
    *c = BoolIfElementPresent{true}
    return nil
}

This way, whenever <hide/> is present and unmarshalling is attempted, it just returns true. If <hide/> is not present, no unmarshalling is attempted and the default value false remains in the struct.

Note that you have to wrap your boolean values in the custom struct every time you work with it, though.

The d.DecodeElement(&v, &start) part seems unnecessary, but if you omit that piece of code you will receive an error message:

xml: (*mypackage.BoolIfElementPresent).UnmarshalXML did not consume entire element

Edit: Simplified version curtesy of @ShogunPanda:

type XMLValues struct {
    Hide BoolIfElementPresent `xml:"hide"`
    Data string               `xml:"data"`
}

type BoolIfElementPresent bool

func (c *BoolIfElementPresent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var v string
    d.DecodeElement(&v, &start)
    *c = true
    return nil
}

Note that you have to compare the booleans by using if xyz == true.