after spending few days playing with this package i have a few notes
which the project maintainers may help me resolve or consider as future
enhancements:
* there is no built-in way to quickly encode in XML the same
hand-crafted structures which can be decoded with xml.Unmarshal. it
would be useful to provide such a function.
* the xml.Unmarshal does not handle embedded structures. this is useful
when specifying structs that share with others some common fields. an
example use-case is Document and Folder which share common Container
properties, which in turn shares common Feature properties with other
KML elements [1]. the current workaround is to copy and paste the same
fields in all sharing structures.
* while the current artifice of specifying a field named XMLName of type
xml.Name for catering for namespaces is adequate for creating Go
Bindings of a given XML Schema, it would be more useful to allow either
(a) more Tags (e.g. the XML element name of the field to give better
contol w/o requiring the definition of a struct just to use the
XMLName), or (b) delegate the encoding/decoding to an interface
implementation if the type of the field being processed supports it.
examples of such interfaces would be:
type XMLEncoder interface {
XMLEncode(in io.Writer) os.Error
}
type XMLDecoder interface {
XMLDecode(out io.Reader) os.Error
}
(i haven't thought thoroughly about these interfaces. they're just here
as an example).
thanks for the bandwidth + cheers;
rsn
[1] http://code.google.com/apis/kml/documentation/kmlreference.html
The same "problem" exists with the json package and has been
thoroughly discussed[1][2]. It's a function of the way embedding and
the reflect package work, and it's not likely to change anytime soon
(to the best of my knowledge). Which is a real shame, IMO.
[1] http://groups.google.com/group/golang-nuts/browse_thread/thread/152fc7d128848a80/7c470daf406e65bb
[2] http://groups.google.com/group/golang-nuts/browse_thread/thread/ad301a5c969f1bac/086f77b237b929da
That'd be great.
> * the xml.Unmarshal does not handle embedded structures. this is useful
> when specifying structs that share with others some common fields. an
> example use-case is Document and Folder which share common Container
> properties, which in turn shares common Feature properties with other
> KML elements [1]. the current workaround is to copy and paste the same
> fields in all sharing structures.
Right. The main issue is that the struct field names can be cased differently
from the XML item names, so the loop that looks for a field to use can't be
replaced by a simple call to FieldByName. It was just easier to implement
by considering a single level of the struct. I think it would be fine
to implement
the deeper lookup here, for exactly the use cases you're asking for, but
be aware that it's a little involved. It would be good to reproduce the usual
Go rules, but with the more relaxed name equivalence. See the implementation
of (*StructType).FieldByName in package reflect.
> * while the current artifice of specifying a field named XMLName of type
> xml.Name for catering for namespaces is adequate for creating Go
> Bindings of a given XML Schema, it would be more useful to allow either
> (a) more Tags (e.g. the XML element name of the field to give better
> contol w/o requiring the definition of a struct just to use the
> XMLName), or (b) delegate the encoding/decoding to an interface
> implementation if the type of the field being processed supports it.
> examples of such interfaces would be:
>
> type XMLEncoder interface {
> XMLEncode(in io.Writer) os.Error
> }
>
> type XMLDecoder interface {
> XMLDecode(out io.Reader) os.Error
> }
>
> (i haven't thought thoroughly about these interfaces. they're just here
> as an example).
Seems like a good idea. The protocol buffer implementation allows
a similar thing, and I'd like to see JSON allow things like this too.
This is probably worth doing as a separate change from the relaxed
name lookup, but something like
type Unmarshaler interface {
UnmarshalXML(p *Parser, start *StartElement) os.Error
}
seems like it would work for the unmarshalling. The StartElement
argument may not be necessary or a good idea - the parser could
just return that as the first token instead.
The form for the Marshaler interface would depend on what Marshal
ends up using internally, but it seems like you'd want something
a little higher level than io.Writer, perhaps *bufio.Writer.
> The same "problem" exists with the json package and has been
> thoroughly discussed[1][2]. It's a function of the way embedding and
> the reflect package work, and it's not likely to change anytime soon
> (to the best of my knowledge). Which is a real shame, IMO.
>
> [1] http://groups.google.com/group/golang-nuts/browse_thread/thread/152fc7d128848a80/7c470daf406e65bb
> [2] http://groups.google.com/group/golang-nuts/browse_thread/thread/ad301a5c969f1bac/086f77b237b929da
These are both discussing not json but Go structure literals,
which you're right are not likely to change anytime soon.
Russ
thanks for the feedback. few comments in-line.
On Mon, 2010-03-29 at 10:12 -0700, Russ Cox wrote:
> @se...@naffah-raif.name:
> > * there is no built-in way to quickly encode in XML the same
> > hand-crafted structures which can be decoded with xml.Unmarshal. it
> > would be useful to provide such a function.
>
> That'd be great.
cool. i'll start work on this unless somebody else is willing to raise
their hand.
> > * the xml.Unmarshal does not handle embedded structures. this is useful
> > when specifying structs that share with others some common fields. an
> > example use-case is Document and Folder which share common Container
> > properties, which in turn shares common Feature properties with other
> > KML elements [1]. the current workaround is to copy and paste the same
> > fields in all sharing structures.
>
> Right. The main issue is that the struct field names can be cased differently
> from the XML item names, so the loop that looks for a field to use can't be
> replaced by a simple call to FieldByName. It was just easier to implement
> by considering a single level of the struct. I think it would be fine
> to implement
> the deeper lookup here, for exactly the use cases you're asking for, but
> be aware that it's a little involved...
indeed. i'm thinking of applying the same heuristic for name matching
as it's currently implemented in 'read.go' for top-level fields.
cheers;
rsn
The tricky part is what happens when there are multiple names that match.
If you have
type Foo struct {
XY int
}
type Bar struct {
Xy int
}
type T struct {
Foo
Bar
}
and you are decoding field "xy" into type T, I suggest following the Go rules
for duplicate names (as implemented in StructType.FieldByName, among
other places), which would exclude both Foo.XY and Bar.Xy, because they
conflict with each other.
(If Bar had XY, then the rule in Go would make T.XY ambiguous and not
an allowed reference. This is the generalization of that to the more relaxed
name matching rules.)
Russ
noted. i'll add a test specifically for this case.
cheers;
rsn