xml marshal with omitempty not handling 0

935 views
Skip to first unread message

Jonathan Pittman

unread,
Oct 4, 2012, 9:34:25 PM10/4/12
to golang-nuts
I do not understand why this does what it does, but take a look at...

http://play.golang.org/p/Oj1pJvCXLo

The output is:
<Param><Val1></Val1><Val2><int>0</int></Val2></Param>

But I think (would like) the output to be:

<Param><Val1><int>0</int></Val1><Val2><int>0</int></Val2></Param>

It works fine if the value is something other than 0.  In my case, I have instances where the value is really supposed to be 0.  If the pointer is nil, I am glad for it to omit the field, but why does it omit if the pointer is not nil and the underlying value is 0?

Jonathan Pittman

unread,
Oct 4, 2012, 9:58:25 PM10/4/12
to golang-nuts
I just found this in the xml package...

- a field with a tag including the "omitempty" option is omitted
  if the field value is empty. The empty values are false, 0, any
  nil pointer or interface value, and any array, slice, map, or
  string of length zero.

So, I guess this makes sense for non-pointer values, but should this be changed to treat a pointer differently?  If the pointer is nil, then omit the field.  If the pointer is not nil, then marshal the underlying value even if it is one of the "empty values."

Jonathan Pittman

unread,
Oct 7, 2012, 10:59:15 AM10/7/12
to golang-nuts
ping

What do you think about this as a possible API change for Go 1.1 for the xml package?

Russ Cox

unread,
Oct 7, 2012, 11:18:54 AM10/7/12
to Jonathan Pittman, golang-nuts
If you don't want it to omit empty values, why not drop the omitempty tag?

http://play.golang.org/p/fcWthm1HtE

Russ

Jonathan Pittman

unread,
Oct 7, 2012, 12:09:08 PM10/7/12
to Russ Cox, golang-nuts
What I was trying to achieve was using a pointer state to determine if something should be included in the marshaling or not.  This was (I thought) working well, until I ran into a situation where I needed to marshal up a 0.  The *int was no longer nil.  So, I expected the underlying 0 to be marshaled, but it was not due to the recursive calling of the printer.marshalValue() method on the underlying Elem with the same fieldInfo settings.

I see what you have done there.  I seem to have misread and misunderstood the marshaling behavior of the xml package.  I think I was under the assumption that a nil value would be marshaled as null (like the json package does) unless the omitempty tag was present.  Of course, now looking at my code example, I was so focused on the difference with the omitempty tag that I did not realize the nil *string was never seen in the output.

Sorry for not RTFMing closer.

Kyle Lemons

unread,
Oct 8, 2012, 7:31:17 PM10/8/12
to Jonathan Pittman, Russ Cox, golang-nuts
On a somewhat related note, this is one of the things about protocol buffers that I find peculiar; that is, the notion that the presence or the absence of a value that is the same as the default (in this case zero) can be distinguished and treated differently.  It strikes me as difficult to ensure that all players in such a system behave properly in all of the corner cases that arise with such a distinction.  I humbly submit to you that if you have the luxury of designing a system, you should treat them both the same :).

--
 
 

krolaw

unread,
Oct 8, 2012, 9:32:39 PM10/8/12
to golan...@googlegroups.com, Jonathan Pittman, Russ Cox
Looks like I have the same issue as Jonathan.  Just thinking about this, if Marshal omits &int(0), then shouldn't Unmarshall create a new &int(0) when the tag is omitted rather than nil?  (Yes &int(0) isn't legal but I don't have the correct jargon to better describe my thoughts).

Anyway, my problem is that I'm creating an online availability engine (for motels), and I'm using as struct similar to:

type Update struct {
Date time.Time
RoomType string
Availability *int `xml:",omitempty"`
Rate *float32 `xml:",omitempty"`
...lots of other optional fields
}

Now, the tags "Availability" and "Rate" etc are optional.  From what Jonathan describes, I either must always set availability (which may not exist in that update - and risk making the room unavailable), OR be unable to make the room unavailable when setting the value to be zero.

I, like Jonathan, thought using an *int instead of an int, would mean the xml package would only check the value, see that the pointer was not nil and display.  I didn't expect it to look deeper...  I mean, the field value itself isn't empty...

I was just about to suggest I might get around it with the XMLMarshal interface, but that only works with JSON.

I'd really rather not have to add a special unavailable tag, as it's not streamlined and will require more work for anyone interfacing my system.

Thoughts?  Thanks.
Reply all
Reply to author
Forward
0 new messages